blob: 0b33f3190e3dbb2d87840c32a7917624d7ce6912 [file] [log] [blame]
Simon Glass793dca32019-10-31 07:42:57 -06001#!/usr/bin/env python3
Tom Rini83d290c2018-05-06 17:58:06 -04002# SPDX-License-Identifier: GPL-2.0+
Masahiro Yamada5a27c732015-05-20 11:36:07 +09003#
4# Author: Masahiro Yamada <yamada.masahiro@socionext.com>
5#
Masahiro Yamada5a27c732015-05-20 11:36:07 +09006
7"""
8Move config options from headers to defconfig files.
9
Simon Glass5c72c0e2021-07-21 21:35:51 -060010See doc/develop/moveconfig.rst for documentation.
Masahiro Yamada5a27c732015-05-20 11:36:07 +090011"""
12
Simon Glassb2e83c62021-12-18 14:54:31 -070013from argparse import ArgumentParser
Markus Klotzbuecherb3192f42020-02-12 20:46:44 +010014import asteval
Simon Glass99b66602017-06-01 19:39:03 -060015import collections
Masahiro Yamada8ba1f5d2016-07-25 19:15:24 +090016import copy
Masahiro Yamadaf2f69812016-07-25 19:15:25 +090017import difflib
Simon Glass84067a52021-12-18 08:09:45 -070018import doctest
Masahiro Yamadac8e1b102016-05-19 15:52:07 +090019import filecmp
Masahiro Yamada5a27c732015-05-20 11:36:07 +090020import fnmatch
Masahiro Yamada0dbc9b52016-10-19 14:39:54 +090021import glob
Masahiro Yamada5a27c732015-05-20 11:36:07 +090022import multiprocessing
Masahiro Yamada5a27c732015-05-20 11:36:07 +090023import os
Simon Glass793dca32019-10-31 07:42:57 -060024import queue
Masahiro Yamada5a27c732015-05-20 11:36:07 +090025import re
26import shutil
27import subprocess
28import sys
29import tempfile
Simon Glassd73fcb12017-06-01 19:39:02 -060030import threading
Masahiro Yamada5a27c732015-05-20 11:36:07 +090031import time
Simon Glass84067a52021-12-18 08:09:45 -070032import unittest
Masahiro Yamada5a27c732015-05-20 11:36:07 +090033
Simon Glass0ede00f2020-04-17 18:09:02 -060034from buildman import bsettings
35from buildman import kconfiglib
36from buildman import toolchain
Simon Glasscb008832017-06-15 21:39:33 -060037
Masahiro Yamada5a27c732015-05-20 11:36:07 +090038SHOW_GNU_MAKE = 'scripts/show-gnu-make'
39SLEEP_TIME=0.03
40
Masahiro Yamada5a27c732015-05-20 11:36:07 +090041STATE_IDLE = 0
42STATE_DEFCONFIG = 1
43STATE_AUTOCONF = 2
Joe Hershberger96464ba2015-05-19 13:21:17 -050044STATE_SAVEDEFCONFIG = 3
Masahiro Yamada5a27c732015-05-20 11:36:07 +090045
46ACTION_MOVE = 0
Masahiro Yamadacc008292016-05-19 15:51:56 +090047ACTION_NO_ENTRY = 1
Masahiro Yamada916224c2016-08-22 22:18:21 +090048ACTION_NO_ENTRY_WARN = 2
49ACTION_NO_CHANGE = 3
Masahiro Yamada5a27c732015-05-20 11:36:07 +090050
51COLOR_BLACK = '0;30'
52COLOR_RED = '0;31'
53COLOR_GREEN = '0;32'
54COLOR_BROWN = '0;33'
55COLOR_BLUE = '0;34'
56COLOR_PURPLE = '0;35'
57COLOR_CYAN = '0;36'
58COLOR_LIGHT_GRAY = '0;37'
59COLOR_DARK_GRAY = '1;30'
60COLOR_LIGHT_RED = '1;31'
61COLOR_LIGHT_GREEN = '1;32'
62COLOR_YELLOW = '1;33'
63COLOR_LIGHT_BLUE = '1;34'
64COLOR_LIGHT_PURPLE = '1;35'
65COLOR_LIGHT_CYAN = '1;36'
66COLOR_WHITE = '1;37'
67
Simon Glassf3b8e642017-06-01 19:39:01 -060068AUTO_CONF_PATH = 'include/config/auto.conf'
Simon Glassd73fcb12017-06-01 19:39:02 -060069CONFIG_DATABASE = 'moveconfig.db'
Simon Glassf3b8e642017-06-01 19:39:01 -060070
Simon Glasscb008832017-06-15 21:39:33 -060071CONFIG_LEN = len('CONFIG_')
Simon Glassf3b8e642017-06-01 19:39:01 -060072
Markus Klotzbuecherb237d352019-05-15 15:15:52 +020073SIZES = {
Simon Glassdaa694d2021-12-18 14:54:30 -070074 'SZ_1': 0x00000001, 'SZ_2': 0x00000002,
75 'SZ_4': 0x00000004, 'SZ_8': 0x00000008,
76 'SZ_16': 0x00000010, 'SZ_32': 0x00000020,
77 'SZ_64': 0x00000040, 'SZ_128': 0x00000080,
78 'SZ_256': 0x00000100, 'SZ_512': 0x00000200,
79 'SZ_1K': 0x00000400, 'SZ_2K': 0x00000800,
80 'SZ_4K': 0x00001000, 'SZ_8K': 0x00002000,
81 'SZ_16K': 0x00004000, 'SZ_32K': 0x00008000,
82 'SZ_64K': 0x00010000, 'SZ_128K': 0x00020000,
83 'SZ_256K': 0x00040000, 'SZ_512K': 0x00080000,
84 'SZ_1M': 0x00100000, 'SZ_2M': 0x00200000,
85 'SZ_4M': 0x00400000, 'SZ_8M': 0x00800000,
86 'SZ_16M': 0x01000000, 'SZ_32M': 0x02000000,
87 'SZ_64M': 0x04000000, 'SZ_128M': 0x08000000,
88 'SZ_256M': 0x10000000, 'SZ_512M': 0x20000000,
89 'SZ_1G': 0x40000000, 'SZ_2G': 0x80000000,
90 'SZ_4G': 0x100000000
Markus Klotzbuecherb237d352019-05-15 15:15:52 +020091}
92
Masahiro Yamada5a27c732015-05-20 11:36:07 +090093### helper functions ###
Masahiro Yamada5a27c732015-05-20 11:36:07 +090094def check_top_directory():
95 """Exit if we are not at the top of source directory."""
96 for f in ('README', 'Licenses'):
97 if not os.path.exists(f):
98 sys.exit('Please run at the top of source directory.')
99
Masahiro Yamadabd63e5b2016-05-19 15:51:54 +0900100def check_clean_directory():
101 """Exit if the source tree is not clean."""
102 for f in ('.config', 'include/config'):
103 if os.path.exists(f):
104 sys.exit("source tree is not clean, please run 'make mrproper'")
105
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900106def get_make_cmd():
107 """Get the command name of GNU Make.
108
109 U-Boot needs GNU Make for building, but the command name is not
110 necessarily "make". (for example, "gmake" on FreeBSD).
111 Returns the most appropriate command name on your system.
112 """
113 process = subprocess.Popen([SHOW_GNU_MAKE], stdout=subprocess.PIPE)
114 ret = process.communicate()
115 if process.returncode:
116 sys.exit('GNU Make not found')
117 return ret[0].rstrip()
118
Simon Glass25f978c2017-06-01 19:38:58 -0600119def get_matched_defconfig(line):
120 """Get the defconfig files that match a pattern
121
122 Args:
123 line: Path or filename to match, e.g. 'configs/snow_defconfig' or
124 'k2*_defconfig'. If no directory is provided, 'configs/' is
125 prepended
126
127 Returns:
128 a list of matching defconfig files
129 """
130 dirname = os.path.dirname(line)
131 if dirname:
132 pattern = line
133 else:
134 pattern = os.path.join('configs', line)
135 return glob.glob(pattern) + glob.glob(pattern + '_defconfig')
136
Masahiro Yamada0dbc9b52016-10-19 14:39:54 +0900137def get_matched_defconfigs(defconfigs_file):
Simon Glassee4e61b2017-06-01 19:38:59 -0600138 """Get all the defconfig files that match the patterns in a file.
139
140 Args:
141 defconfigs_file: File containing a list of defconfigs to process, or
142 '-' to read the list from stdin
143
144 Returns:
145 A list of paths to defconfig files, with no duplicates
146 """
Masahiro Yamada0dbc9b52016-10-19 14:39:54 +0900147 defconfigs = []
Simon Glassee4e61b2017-06-01 19:38:59 -0600148 if defconfigs_file == '-':
149 fd = sys.stdin
150 defconfigs_file = 'stdin'
151 else:
152 fd = open(defconfigs_file)
153 for i, line in enumerate(fd):
Masahiro Yamada0dbc9b52016-10-19 14:39:54 +0900154 line = line.strip()
155 if not line:
156 continue # skip blank lines silently
Simon Glass2ddd85d2017-06-15 21:39:31 -0600157 if ' ' in line:
158 line = line.split(' ')[0] # handle 'git log' input
Simon Glass25f978c2017-06-01 19:38:58 -0600159 matched = get_matched_defconfig(line)
Masahiro Yamada0dbc9b52016-10-19 14:39:54 +0900160 if not matched:
Simon Glass793dca32019-10-31 07:42:57 -0600161 print("warning: %s:%d: no defconfig matched '%s'" % \
162 (defconfigs_file, i + 1, line), file=sys.stderr)
Masahiro Yamada0dbc9b52016-10-19 14:39:54 +0900163
164 defconfigs += matched
165
166 # use set() to drop multiple matching
167 return [ defconfig[len('configs') + 1:] for defconfig in set(defconfigs) ]
168
Masahiro Yamada684c3062016-07-25 19:15:28 +0900169def get_all_defconfigs():
170 """Get all the defconfig files under the configs/ directory."""
171 defconfigs = []
172 for (dirpath, dirnames, filenames) in os.walk('configs'):
173 dirpath = dirpath[len('configs') + 1:]
174 for filename in fnmatch.filter(filenames, '*_defconfig'):
175 defconfigs.append(os.path.join(dirpath, filename))
176
177 return defconfigs
178
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900179def color_text(color_enabled, color, string):
180 """Return colored string."""
181 if color_enabled:
Masahiro Yamada1d085562016-05-19 15:52:02 +0900182 # LF should not be surrounded by the escape sequence.
183 # Otherwise, additional whitespace or line-feed might be printed.
184 return '\n'.join([ '\033[' + color + 'm' + s + '\033[0m' if s else ''
185 for s in string.split('\n') ])
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900186 else:
187 return string
188
Masahiro Yamadae9ea1222016-07-25 19:15:26 +0900189def show_diff(a, b, file_path, color_enabled):
Masahiro Yamadaf2f69812016-07-25 19:15:25 +0900190 """Show unidified diff.
191
192 Arguments:
193 a: A list of lines (before)
194 b: A list of lines (after)
195 file_path: Path to the file
Masahiro Yamadae9ea1222016-07-25 19:15:26 +0900196 color_enabled: Display the diff in color
Masahiro Yamadaf2f69812016-07-25 19:15:25 +0900197 """
198
199 diff = difflib.unified_diff(a, b,
200 fromfile=os.path.join('a', file_path),
201 tofile=os.path.join('b', file_path))
202
203 for line in diff:
Masahiro Yamadae9ea1222016-07-25 19:15:26 +0900204 if line[0] == '-' and line[1] != '-':
Simon Glass793dca32019-10-31 07:42:57 -0600205 print(color_text(color_enabled, COLOR_RED, line), end=' ')
Masahiro Yamadae9ea1222016-07-25 19:15:26 +0900206 elif line[0] == '+' and line[1] != '+':
Simon Glass793dca32019-10-31 07:42:57 -0600207 print(color_text(color_enabled, COLOR_GREEN, line), end=' ')
Masahiro Yamadae9ea1222016-07-25 19:15:26 +0900208 else:
Simon Glass793dca32019-10-31 07:42:57 -0600209 print(line, end=' ')
Masahiro Yamadaf2f69812016-07-25 19:15:25 +0900210
Masahiro Yamada8ba1f5d2016-07-25 19:15:24 +0900211def extend_matched_lines(lines, matched, pre_patterns, post_patterns, extend_pre,
212 extend_post):
213 """Extend matched lines if desired patterns are found before/after already
214 matched lines.
215
216 Arguments:
217 lines: A list of lines handled.
218 matched: A list of line numbers that have been already matched.
219 (will be updated by this function)
220 pre_patterns: A list of regular expression that should be matched as
221 preamble.
222 post_patterns: A list of regular expression that should be matched as
223 postamble.
224 extend_pre: Add the line number of matched preamble to the matched list.
225 extend_post: Add the line number of matched postamble to the matched list.
226 """
227 extended_matched = []
228
229 j = matched[0]
230
231 for i in matched:
232 if i == 0 or i < j:
233 continue
234 j = i
235 while j in matched:
236 j += 1
237 if j >= len(lines):
238 break
239
240 for p in pre_patterns:
241 if p.search(lines[i - 1]):
242 break
243 else:
244 # not matched
245 continue
246
247 for p in post_patterns:
248 if p.search(lines[j]):
249 break
250 else:
251 # not matched
252 continue
253
254 if extend_pre:
255 extended_matched.append(i - 1)
256 if extend_post:
257 extended_matched.append(j)
258
259 matched += extended_matched
260 matched.sort()
261
Simon Glassb2e83c62021-12-18 14:54:31 -0700262def confirm(args, prompt):
263 if not args.yes:
Chris Packham85edfc12017-05-02 21:30:46 +1200264 while True:
Simon Glass793dca32019-10-31 07:42:57 -0600265 choice = input('{} [y/n]: '.format(prompt))
Chris Packham85edfc12017-05-02 21:30:46 +1200266 choice = choice.lower()
Simon Glass793dca32019-10-31 07:42:57 -0600267 print(choice)
Chris Packham85edfc12017-05-02 21:30:46 +1200268 if choice == 'y' or choice == 'n':
269 break
270
271 if choice == 'n':
272 return False
273
274 return True
275
Simon Glassb2e83c62021-12-18 14:54:31 -0700276def cleanup_empty_blocks(header_path, args):
Chris Packham4d9dbb12019-01-30 20:23:16 +1300277 """Clean up empty conditional blocks
278
279 Arguments:
280 header_path: path to the cleaned file.
Simon Glassb2e83c62021-12-18 14:54:31 -0700281 args: program arguments
Chris Packham4d9dbb12019-01-30 20:23:16 +1300282 """
283 pattern = re.compile(r'^\s*#\s*if.*$\n^\s*#\s*endif.*$\n*', flags=re.M)
284 with open(header_path) as f:
Simon Glass7570d9b2021-03-26 16:17:29 +1300285 try:
286 data = f.read()
287 except UnicodeDecodeError as e:
288 print("Failed on file %s': %s" % (header_path, e))
289 return
Chris Packham4d9dbb12019-01-30 20:23:16 +1300290
291 new_data = pattern.sub('\n', data)
292
293 show_diff(data.splitlines(True), new_data.splitlines(True), header_path,
Simon Glassb2e83c62021-12-18 14:54:31 -0700294 args.color)
Chris Packham4d9dbb12019-01-30 20:23:16 +1300295
Simon Glassb2e83c62021-12-18 14:54:31 -0700296 if args.dry_run:
Chris Packham4d9dbb12019-01-30 20:23:16 +1300297 return
298
299 with open(header_path, 'w') as f:
300 f.write(new_data)
301
Simon Glassb2e83c62021-12-18 14:54:31 -0700302def cleanup_one_header(header_path, patterns, args):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900303 """Clean regex-matched lines away from a file.
304
305 Arguments:
306 header_path: path to the cleaned file.
307 patterns: list of regex patterns. Any lines matching to these
308 patterns are deleted.
Simon Glassb2e83c62021-12-18 14:54:31 -0700309 args: program arguments
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900310 """
311 with open(header_path) as f:
Simon Glass7570d9b2021-03-26 16:17:29 +1300312 try:
313 lines = f.readlines()
314 except UnicodeDecodeError as e:
315 print("Failed on file %s': %s" % (header_path, e))
316 return
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900317
318 matched = []
319 for i, line in enumerate(lines):
Masahiro Yamadaa3a779f2016-07-25 19:15:27 +0900320 if i - 1 in matched and lines[i - 1][-2:] == '\\\n':
321 matched.append(i)
322 continue
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900323 for pattern in patterns:
Masahiro Yamada8ba1f5d2016-07-25 19:15:24 +0900324 if pattern.search(line):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900325 matched.append(i)
326 break
327
Masahiro Yamada8ba1f5d2016-07-25 19:15:24 +0900328 if not matched:
329 return
330
331 # remove empty #ifdef ... #endif, successive blank lines
332 pattern_if = re.compile(r'#\s*if(def|ndef)?\W') # #if, #ifdef, #ifndef
333 pattern_elif = re.compile(r'#\s*el(if|se)\W') # #elif, #else
334 pattern_endif = re.compile(r'#\s*endif\W') # #endif
335 pattern_blank = re.compile(r'^\s*$') # empty line
336
337 while True:
338 old_matched = copy.copy(matched)
339 extend_matched_lines(lines, matched, [pattern_if],
340 [pattern_endif], True, True)
341 extend_matched_lines(lines, matched, [pattern_elif],
342 [pattern_elif, pattern_endif], True, False)
343 extend_matched_lines(lines, matched, [pattern_if, pattern_elif],
344 [pattern_blank], False, True)
345 extend_matched_lines(lines, matched, [pattern_blank],
346 [pattern_elif, pattern_endif], True, False)
347 extend_matched_lines(lines, matched, [pattern_blank],
348 [pattern_blank], True, False)
349 if matched == old_matched:
350 break
351
Masahiro Yamadaf2f69812016-07-25 19:15:25 +0900352 tolines = copy.copy(lines)
353
354 for i in reversed(matched):
355 tolines.pop(i)
356
Simon Glassb2e83c62021-12-18 14:54:31 -0700357 show_diff(lines, tolines, header_path, args.color)
Masahiro Yamada8ba1f5d2016-07-25 19:15:24 +0900358
Simon Glassb2e83c62021-12-18 14:54:31 -0700359 if args.dry_run:
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900360 return
361
362 with open(header_path, 'w') as f:
Masahiro Yamadaf2f69812016-07-25 19:15:25 +0900363 for line in tolines:
364 f.write(line)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900365
Simon Glassb2e83c62021-12-18 14:54:31 -0700366def cleanup_headers(configs, args):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900367 """Delete config defines from board headers.
368
369 Arguments:
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900370 configs: A list of CONFIGs to remove.
Simon Glassb2e83c62021-12-18 14:54:31 -0700371 args: program arguments
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900372 """
Simon Glassb2e83c62021-12-18 14:54:31 -0700373 if not confirm(args, 'Clean up headers?'):
Chris Packham85edfc12017-05-02 21:30:46 +1200374 return
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900375
376 patterns = []
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900377 for config in configs:
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900378 patterns.append(re.compile(r'#\s*define\s+%s\W' % config))
379 patterns.append(re.compile(r'#\s*undef\s+%s\W' % config))
380
Joe Hershberger60727f52015-05-19 13:21:21 -0500381 for dir in 'include', 'arch', 'board':
382 for (dirpath, dirnames, filenames) in os.walk(dir):
Masahiro Yamadadc6de502016-07-25 19:15:22 +0900383 if dirpath == os.path.join('include', 'generated'):
384 continue
Joe Hershberger60727f52015-05-19 13:21:21 -0500385 for filename in filenames:
Simon Glassa38cc172020-08-11 11:23:34 -0600386 if not filename.endswith(('~', '.dts', '.dtsi', '.bin',
Trevor Woernerdc514d72021-03-15 12:01:33 -0400387 '.elf','.aml','.dat')):
Chris Packham4d9dbb12019-01-30 20:23:16 +1300388 header_path = os.path.join(dirpath, filename)
Tom Rini02b56702019-11-10 21:19:37 -0500389 # This file contains UTF-16 data and no CONFIG symbols
390 if header_path == 'include/video_font_data.h':
391 continue
Simon Glassb2e83c62021-12-18 14:54:31 -0700392 cleanup_one_header(header_path, patterns, args)
393 cleanup_empty_blocks(header_path, args)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900394
Simon Glassb2e83c62021-12-18 14:54:31 -0700395def cleanup_one_extra_option(defconfig_path, configs, args):
Masahiro Yamada9ab02962016-07-25 19:15:29 +0900396 """Delete config defines in CONFIG_SYS_EXTRA_OPTIONS in one defconfig file.
397
398 Arguments:
399 defconfig_path: path to the cleaned defconfig file.
400 configs: A list of CONFIGs to remove.
Simon Glassb2e83c62021-12-18 14:54:31 -0700401 args: program arguments
Masahiro Yamada9ab02962016-07-25 19:15:29 +0900402 """
403
404 start = 'CONFIG_SYS_EXTRA_OPTIONS="'
405 end = '"\n'
406
407 with open(defconfig_path) as f:
408 lines = f.readlines()
409
410 for i, line in enumerate(lines):
411 if line.startswith(start) and line.endswith(end):
412 break
413 else:
414 # CONFIG_SYS_EXTRA_OPTIONS was not found in this defconfig
415 return
416
417 old_tokens = line[len(start):-len(end)].split(',')
418 new_tokens = []
419
420 for token in old_tokens:
421 pos = token.find('=')
422 if not (token[:pos] if pos >= 0 else token) in configs:
423 new_tokens.append(token)
424
425 if new_tokens == old_tokens:
426 return
427
428 tolines = copy.copy(lines)
429
430 if new_tokens:
431 tolines[i] = start + ','.join(new_tokens) + end
432 else:
433 tolines.pop(i)
434
Simon Glassb2e83c62021-12-18 14:54:31 -0700435 show_diff(lines, tolines, defconfig_path, args.color)
Masahiro Yamada9ab02962016-07-25 19:15:29 +0900436
Simon Glassb2e83c62021-12-18 14:54:31 -0700437 if args.dry_run:
Masahiro Yamada9ab02962016-07-25 19:15:29 +0900438 return
439
440 with open(defconfig_path, 'w') as f:
441 for line in tolines:
442 f.write(line)
443
Simon Glassb2e83c62021-12-18 14:54:31 -0700444def cleanup_extra_options(configs, args):
Masahiro Yamada9ab02962016-07-25 19:15:29 +0900445 """Delete config defines in CONFIG_SYS_EXTRA_OPTIONS in defconfig files.
446
447 Arguments:
448 configs: A list of CONFIGs to remove.
Simon Glassb2e83c62021-12-18 14:54:31 -0700449 args: program arguments
Masahiro Yamada9ab02962016-07-25 19:15:29 +0900450 """
Simon Glassb2e83c62021-12-18 14:54:31 -0700451 if not confirm(args, 'Clean up CONFIG_SYS_EXTRA_OPTIONS?'):
Chris Packham85edfc12017-05-02 21:30:46 +1200452 return
Masahiro Yamada9ab02962016-07-25 19:15:29 +0900453
454 configs = [ config[len('CONFIG_'):] for config in configs ]
455
456 defconfigs = get_all_defconfigs()
457
458 for defconfig in defconfigs:
459 cleanup_one_extra_option(os.path.join('configs', defconfig), configs,
Simon Glassb2e83c62021-12-18 14:54:31 -0700460 args)
Masahiro Yamada9ab02962016-07-25 19:15:29 +0900461
Simon Glassb2e83c62021-12-18 14:54:31 -0700462def cleanup_whitelist(configs, args):
Chris Packhamca438342017-05-02 21:30:47 +1200463 """Delete config whitelist entries
464
465 Arguments:
466 configs: A list of CONFIGs to remove.
Simon Glassb2e83c62021-12-18 14:54:31 -0700467 args: program arguments
Chris Packhamca438342017-05-02 21:30:47 +1200468 """
Simon Glassb2e83c62021-12-18 14:54:31 -0700469 if not confirm(args, 'Clean up whitelist entries?'):
Chris Packhamca438342017-05-02 21:30:47 +1200470 return
471
472 with open(os.path.join('scripts', 'config_whitelist.txt')) as f:
473 lines = f.readlines()
474
475 lines = [x for x in lines if x.strip() not in configs]
476
477 with open(os.path.join('scripts', 'config_whitelist.txt'), 'w') as f:
478 f.write(''.join(lines))
479
Chris Packhamf90df592017-05-02 21:30:48 +1200480def find_matching(patterns, line):
481 for pat in patterns:
482 if pat.search(line):
483 return True
484 return False
485
Simon Glassb2e83c62021-12-18 14:54:31 -0700486def cleanup_readme(configs, args):
Chris Packhamf90df592017-05-02 21:30:48 +1200487 """Delete config description in README
488
489 Arguments:
490 configs: A list of CONFIGs to remove.
Simon Glassb2e83c62021-12-18 14:54:31 -0700491 args: program arguments
Chris Packhamf90df592017-05-02 21:30:48 +1200492 """
Simon Glassb2e83c62021-12-18 14:54:31 -0700493 if not confirm(args, 'Clean up README?'):
Chris Packhamf90df592017-05-02 21:30:48 +1200494 return
495
496 patterns = []
497 for config in configs:
498 patterns.append(re.compile(r'^\s+%s' % config))
499
500 with open('README') as f:
501 lines = f.readlines()
502
503 found = False
504 newlines = []
505 for line in lines:
506 if not found:
507 found = find_matching(patterns, line)
508 if found:
509 continue
510
511 if found and re.search(r'^\s+CONFIG', line):
512 found = False
513
514 if not found:
515 newlines.append(line)
516
517 with open('README', 'w') as f:
518 f.write(''.join(newlines))
519
Markus Klotzbuecherb237d352019-05-15 15:15:52 +0200520def try_expand(line):
521 """If value looks like an expression, try expanding it
522 Otherwise just return the existing value
523 """
524 if line.find('=') == -1:
525 return line
526
527 try:
Markus Klotzbuecherb3192f42020-02-12 20:46:44 +0100528 aeval = asteval.Interpreter( usersyms=SIZES, minimal=True )
Markus Klotzbuecherb237d352019-05-15 15:15:52 +0200529 cfg, val = re.split("=", line)
530 val= val.strip('\"')
Simon Glassdaa694d2021-12-18 14:54:30 -0700531 if re.search(r'[*+-/]|<<|SZ_+|\(([^\)]+)\)', val):
Markus Klotzbuecherb3192f42020-02-12 20:46:44 +0100532 newval = hex(aeval(val))
Simon Glassdaa694d2021-12-18 14:54:30 -0700533 print('\tExpanded expression %s to %s' % (val, newval))
Markus Klotzbuecherb237d352019-05-15 15:15:52 +0200534 return cfg+'='+newval
535 except:
Simon Glassdaa694d2021-12-18 14:54:30 -0700536 print('\tFailed to expand expression in %s' % line)
Markus Klotzbuecherb237d352019-05-15 15:15:52 +0200537
538 return line
539
Chris Packhamca438342017-05-02 21:30:47 +1200540
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900541### classes ###
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +0900542class Progress:
543
544 """Progress Indicator"""
545
546 def __init__(self, total):
547 """Create a new progress indicator.
548
549 Arguments:
550 total: A number of defconfig files to process.
551 """
552 self.current = 0
553 self.total = total
554
555 def inc(self):
556 """Increment the number of processed defconfig files."""
557
558 self.current += 1
559
560 def show(self):
561 """Display the progress."""
Simon Glass793dca32019-10-31 07:42:57 -0600562 print(' %d defconfigs out of %d\r' % (self.current, self.total), end=' ')
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +0900563 sys.stdout.flush()
564
Simon Glasscb008832017-06-15 21:39:33 -0600565
566class KconfigScanner:
567 """Kconfig scanner."""
568
569 def __init__(self):
570 """Scan all the Kconfig files and create a Config object."""
571 # Define environment variables referenced from Kconfig
572 os.environ['srctree'] = os.getcwd()
573 os.environ['UBOOTVERSION'] = 'dummy'
574 os.environ['KCONFIG_OBJDIR'] = ''
Tom Rini65e05dd2019-09-20 17:42:09 -0400575 self.conf = kconfiglib.Kconfig()
Simon Glasscb008832017-06-15 21:39:33 -0600576
577
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900578class KconfigParser:
579
580 """A parser of .config and include/autoconf.mk."""
581
582 re_arch = re.compile(r'CONFIG_SYS_ARCH="(.*)"')
583 re_cpu = re.compile(r'CONFIG_SYS_CPU="(.*)"')
584
Simon Glassb2e83c62021-12-18 14:54:31 -0700585 def __init__(self, configs, args, build_dir):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900586 """Create a new parser.
587
588 Arguments:
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900589 configs: A list of CONFIGs to move.
Simon Glassb2e83c62021-12-18 14:54:31 -0700590 args: program arguments
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900591 build_dir: Build directory.
592 """
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900593 self.configs = configs
Simon Glassb2e83c62021-12-18 14:54:31 -0700594 self.args = args
Masahiro Yamada1f169922016-05-19 15:52:00 +0900595 self.dotconfig = os.path.join(build_dir, '.config')
596 self.autoconf = os.path.join(build_dir, 'include', 'autoconf.mk')
Masahiro Yamada07913d12016-08-22 22:18:22 +0900597 self.spl_autoconf = os.path.join(build_dir, 'spl', 'include',
598 'autoconf.mk')
Simon Glassf3b8e642017-06-01 19:39:01 -0600599 self.config_autoconf = os.path.join(build_dir, AUTO_CONF_PATH)
Masahiro Yamada5da4f852016-05-19 15:52:06 +0900600 self.defconfig = os.path.join(build_dir, 'defconfig')
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900601
Simon Glass6821a742017-07-10 14:47:47 -0600602 def get_arch(self):
603 """Parse .config file and return the architecture.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900604
605 Returns:
Simon Glass6821a742017-07-10 14:47:47 -0600606 Architecture name (e.g. 'arm').
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900607 """
608 arch = ''
609 cpu = ''
Masahiro Yamada1f169922016-05-19 15:52:00 +0900610 for line in open(self.dotconfig):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900611 m = self.re_arch.match(line)
612 if m:
613 arch = m.group(1)
614 continue
615 m = self.re_cpu.match(line)
616 if m:
617 cpu = m.group(1)
618
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +0900619 if not arch:
620 return None
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900621
622 # fix-up for aarch64
623 if arch == 'arm' and cpu == 'armv8':
624 arch = 'aarch64'
625
Simon Glass6821a742017-07-10 14:47:47 -0600626 return arch
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900627
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900628 def parse_one_config(self, config, dotconfig_lines, autoconf_lines):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900629 """Parse .config, defconfig, include/autoconf.mk for one config.
630
631 This function looks for the config options in the lines from
632 defconfig, .config, and include/autoconf.mk in order to decide
633 which action should be taken for this defconfig.
634
635 Arguments:
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900636 config: CONFIG name to parse.
Masahiro Yamadacc008292016-05-19 15:51:56 +0900637 dotconfig_lines: lines from the .config file.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900638 autoconf_lines: lines from the include/autoconf.mk file.
639
640 Returns:
641 A tupple of the action for this defconfig and the line
642 matched for the config.
643 """
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900644 not_set = '# %s is not set' % config
645
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900646 for line in autoconf_lines:
647 line = line.rstrip()
648 if line.startswith(config + '='):
Masahiro Yamadacc008292016-05-19 15:51:56 +0900649 new_val = line
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900650 break
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900651 else:
Masahiro Yamadacc008292016-05-19 15:51:56 +0900652 new_val = not_set
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900653
Markus Klotzbuecherb237d352019-05-15 15:15:52 +0200654 new_val = try_expand(new_val)
655
Masahiro Yamada916224c2016-08-22 22:18:21 +0900656 for line in dotconfig_lines:
657 line = line.rstrip()
658 if line.startswith(config + '=') or line == not_set:
659 old_val = line
660 break
661 else:
662 if new_val == not_set:
663 return (ACTION_NO_ENTRY, config)
664 else:
665 return (ACTION_NO_ENTRY_WARN, config)
666
Masahiro Yamadacc008292016-05-19 15:51:56 +0900667 # If this CONFIG is neither bool nor trisate
668 if old_val[-2:] != '=y' and old_val[-2:] != '=m' and old_val != not_set:
669 # tools/scripts/define2mk.sed changes '1' to 'y'.
670 # This is a problem if the CONFIG is int type.
671 # Check the type in Kconfig and handle it correctly.
672 if new_val[-2:] == '=y':
673 new_val = new_val[:-1] + '1'
674
Masahiro Yamada50301592016-06-15 14:33:50 +0900675 return (ACTION_NO_CHANGE if old_val == new_val else ACTION_MOVE,
676 new_val)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900677
Masahiro Yamada1d085562016-05-19 15:52:02 +0900678 def update_dotconfig(self):
Masahiro Yamada6ff36d22016-05-19 15:51:50 +0900679 """Parse files for the config options and update the .config.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900680
Masahiro Yamadacc008292016-05-19 15:51:56 +0900681 This function parses the generated .config and include/autoconf.mk
682 searching the target options.
Masahiro Yamada6ff36d22016-05-19 15:51:50 +0900683 Move the config option(s) to the .config as needed.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900684
685 Arguments:
686 defconfig: defconfig name.
Masahiro Yamada522e8dc2016-05-19 15:52:01 +0900687
688 Returns:
Masahiro Yamada7fb0bac2016-05-19 15:52:04 +0900689 Return a tuple of (updated flag, log string).
690 The "updated flag" is True if the .config was updated, False
691 otherwise. The "log string" shows what happend to the .config.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900692 """
693
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900694 results = []
Masahiro Yamada7fb0bac2016-05-19 15:52:04 +0900695 updated = False
Masahiro Yamada916224c2016-08-22 22:18:21 +0900696 suspicious = False
Masahiro Yamada07913d12016-08-22 22:18:22 +0900697 rm_files = [self.config_autoconf, self.autoconf]
698
Simon Glassb2e83c62021-12-18 14:54:31 -0700699 if self.args.spl:
Masahiro Yamada07913d12016-08-22 22:18:22 +0900700 if os.path.exists(self.spl_autoconf):
701 autoconf_path = self.spl_autoconf
702 rm_files.append(self.spl_autoconf)
703 else:
704 for f in rm_files:
705 os.remove(f)
706 return (updated, suspicious,
Simon Glassb2e83c62021-12-18 14:54:31 -0700707 color_text(self.args.color, COLOR_BROWN,
Masahiro Yamada07913d12016-08-22 22:18:22 +0900708 "SPL is not enabled. Skipped.") + '\n')
709 else:
710 autoconf_path = self.autoconf
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900711
Masahiro Yamada1f169922016-05-19 15:52:00 +0900712 with open(self.dotconfig) as f:
Masahiro Yamadacc008292016-05-19 15:51:56 +0900713 dotconfig_lines = f.readlines()
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900714
Masahiro Yamada07913d12016-08-22 22:18:22 +0900715 with open(autoconf_path) as f:
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900716 autoconf_lines = f.readlines()
717
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900718 for config in self.configs:
719 result = self.parse_one_config(config, dotconfig_lines,
Joe Hershberger96464ba2015-05-19 13:21:17 -0500720 autoconf_lines)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900721 results.append(result)
722
723 log = ''
724
725 for (action, value) in results:
726 if action == ACTION_MOVE:
727 actlog = "Move '%s'" % value
728 log_color = COLOR_LIGHT_GREEN
Masahiro Yamadacc008292016-05-19 15:51:56 +0900729 elif action == ACTION_NO_ENTRY:
Simon Glassdaa694d2021-12-18 14:54:30 -0700730 actlog = '%s is not defined in Kconfig. Do nothing.' % value
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900731 log_color = COLOR_LIGHT_BLUE
Masahiro Yamada916224c2016-08-22 22:18:21 +0900732 elif action == ACTION_NO_ENTRY_WARN:
Simon Glassdaa694d2021-12-18 14:54:30 -0700733 actlog = '%s is not defined in Kconfig (suspicious). Do nothing.' % value
Masahiro Yamada916224c2016-08-22 22:18:21 +0900734 log_color = COLOR_YELLOW
735 suspicious = True
Masahiro Yamadacc008292016-05-19 15:51:56 +0900736 elif action == ACTION_NO_CHANGE:
737 actlog = "'%s' is the same as the define in Kconfig. Do nothing." \
738 % value
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900739 log_color = COLOR_LIGHT_PURPLE
Masahiro Yamada07913d12016-08-22 22:18:22 +0900740 elif action == ACTION_SPL_NOT_EXIST:
Simon Glassdaa694d2021-12-18 14:54:30 -0700741 actlog = 'SPL is not enabled for this defconfig. Skip.'
Masahiro Yamada07913d12016-08-22 22:18:22 +0900742 log_color = COLOR_PURPLE
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900743 else:
Simon Glassdaa694d2021-12-18 14:54:30 -0700744 sys.exit('Internal Error. This should not happen.')
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900745
Simon Glassb2e83c62021-12-18 14:54:31 -0700746 log += color_text(self.args.color, log_color, actlog) + '\n'
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900747
Masahiro Yamada1f169922016-05-19 15:52:00 +0900748 with open(self.dotconfig, 'a') as f:
Masahiro Yamadae423d172016-05-19 15:51:49 +0900749 for (action, value) in results:
750 if action == ACTION_MOVE:
751 f.write(value + '\n')
Masahiro Yamada7fb0bac2016-05-19 15:52:04 +0900752 updated = True
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900753
Masahiro Yamada5da4f852016-05-19 15:52:06 +0900754 self.results = results
Masahiro Yamada07913d12016-08-22 22:18:22 +0900755 for f in rm_files:
756 os.remove(f)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900757
Masahiro Yamada916224c2016-08-22 22:18:21 +0900758 return (updated, suspicious, log)
Masahiro Yamada522e8dc2016-05-19 15:52:01 +0900759
Masahiro Yamada5da4f852016-05-19 15:52:06 +0900760 def check_defconfig(self):
761 """Check the defconfig after savedefconfig
762
763 Returns:
764 Return additional log if moved CONFIGs were removed again by
765 'make savedefconfig'.
766 """
767
768 log = ''
769
770 with open(self.defconfig) as f:
771 defconfig_lines = f.readlines()
772
773 for (action, value) in self.results:
774 if action != ACTION_MOVE:
775 continue
776 if not value + '\n' in defconfig_lines:
Simon Glassb2e83c62021-12-18 14:54:31 -0700777 log += color_text(self.args.color, COLOR_YELLOW,
Masahiro Yamada5da4f852016-05-19 15:52:06 +0900778 "'%s' was removed by savedefconfig.\n" %
779 value)
780
781 return log
782
Simon Glassd73fcb12017-06-01 19:39:02 -0600783
784class DatabaseThread(threading.Thread):
785 """This thread processes results from Slot threads.
786
787 It collects the data in the master config directary. There is only one
788 result thread, and this helps to serialise the build output.
789 """
790 def __init__(self, config_db, db_queue):
791 """Set up a new result thread
792
793 Args:
794 builder: Builder which will be sent each result
795 """
796 threading.Thread.__init__(self)
797 self.config_db = config_db
798 self.db_queue= db_queue
799
800 def run(self):
801 """Called to start up the result thread.
802
803 We collect the next result job and pass it on to the build.
804 """
805 while True:
806 defconfig, configs = self.db_queue.get()
807 self.config_db[defconfig] = configs
808 self.db_queue.task_done()
809
810
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900811class Slot:
812
813 """A slot to store a subprocess.
814
815 Each instance of this class handles one subprocess.
816 This class is useful to control multiple threads
817 for faster processing.
818 """
819
Simon Glassb2e83c62021-12-18 14:54:31 -0700820 def __init__(self, toolchains, configs, args, progress, devnull,
Simon Glass6821a742017-07-10 14:47:47 -0600821 make_cmd, reference_src_dir, db_queue):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900822 """Create a new process slot.
823
824 Arguments:
Simon Glass6821a742017-07-10 14:47:47 -0600825 toolchains: Toolchains object containing toolchains.
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900826 configs: A list of CONFIGs to move.
Simon Glassb2e83c62021-12-18 14:54:31 -0700827 args: Program arguments
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +0900828 progress: A progress indicator.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900829 devnull: A file object of '/dev/null'.
830 make_cmd: command name of GNU Make.
Joe Hershberger6b96c1a2016-06-10 14:53:32 -0500831 reference_src_dir: Determine the true starting config state from this
832 source tree.
Simon Glassd73fcb12017-06-01 19:39:02 -0600833 db_queue: output queue to write config info for the database
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900834 """
Simon Glass6821a742017-07-10 14:47:47 -0600835 self.toolchains = toolchains
Simon Glassb2e83c62021-12-18 14:54:31 -0700836 self.args = args
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +0900837 self.progress = progress
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900838 self.build_dir = tempfile.mkdtemp()
839 self.devnull = devnull
840 self.make_cmd = (make_cmd, 'O=' + self.build_dir)
Joe Hershberger6b96c1a2016-06-10 14:53:32 -0500841 self.reference_src_dir = reference_src_dir
Simon Glassd73fcb12017-06-01 19:39:02 -0600842 self.db_queue = db_queue
Simon Glassb2e83c62021-12-18 14:54:31 -0700843 self.parser = KconfigParser(configs, args, self.build_dir)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900844 self.state = STATE_IDLE
Masahiro Yamada09c6c062016-08-22 22:18:20 +0900845 self.failed_boards = set()
846 self.suspicious_boards = set()
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900847
848 def __del__(self):
849 """Delete the working directory
850
851 This function makes sure the temporary directory is cleaned away
852 even if Python suddenly dies due to error. It should be done in here
Joe Hershbergerf2dae752016-06-10 14:53:29 -0500853 because it is guaranteed the destructor is always invoked when the
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900854 instance of the class gets unreferenced.
855
856 If the subprocess is still running, wait until it finishes.
857 """
858 if self.state != STATE_IDLE:
859 while self.ps.poll() == None:
860 pass
861 shutil.rmtree(self.build_dir)
862
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +0900863 def add(self, defconfig):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900864 """Assign a new subprocess for defconfig and add it to the slot.
865
866 If the slot is vacant, create a new subprocess for processing the
867 given defconfig and add it to the slot. Just returns False if
868 the slot is occupied (i.e. the current subprocess is still running).
869
870 Arguments:
871 defconfig: defconfig name.
872
873 Returns:
874 Return True on success or False on failure
875 """
876 if self.state != STATE_IDLE:
877 return False
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900878
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900879 self.defconfig = defconfig
Masahiro Yamada1d085562016-05-19 15:52:02 +0900880 self.log = ''
Masahiro Yamadaf432c332016-06-15 14:33:52 +0900881 self.current_src_dir = self.reference_src_dir
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900882 self.do_defconfig()
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900883 return True
884
885 def poll(self):
886 """Check the status of the subprocess and handle it as needed.
887
888 Returns True if the slot is vacant (i.e. in idle state).
889 If the configuration is successfully finished, assign a new
890 subprocess to build include/autoconf.mk.
891 If include/autoconf.mk is generated, invoke the parser to
Masahiro Yamada7fb0bac2016-05-19 15:52:04 +0900892 parse the .config and the include/autoconf.mk, moving
893 config options to the .config as needed.
894 If the .config was updated, run "make savedefconfig" to sync
895 it, update the original defconfig, and then set the slot back
896 to the idle state.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900897
898 Returns:
899 Return True if the subprocess is terminated, False otherwise
900 """
901 if self.state == STATE_IDLE:
902 return True
903
904 if self.ps.poll() == None:
905 return False
906
907 if self.ps.poll() != 0:
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900908 self.handle_error()
909 elif self.state == STATE_DEFCONFIG:
Masahiro Yamadaf432c332016-06-15 14:33:52 +0900910 if self.reference_src_dir and not self.current_src_dir:
Joe Hershberger6b96c1a2016-06-10 14:53:32 -0500911 self.do_savedefconfig()
912 else:
913 self.do_autoconf()
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900914 elif self.state == STATE_AUTOCONF:
Masahiro Yamadaf432c332016-06-15 14:33:52 +0900915 if self.current_src_dir:
916 self.current_src_dir = None
Joe Hershberger6b96c1a2016-06-10 14:53:32 -0500917 self.do_defconfig()
Simon Glassb2e83c62021-12-18 14:54:31 -0700918 elif self.args.build_db:
Simon Glassd73fcb12017-06-01 19:39:02 -0600919 self.do_build_db()
Joe Hershberger6b96c1a2016-06-10 14:53:32 -0500920 else:
921 self.do_savedefconfig()
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900922 elif self.state == STATE_SAVEDEFCONFIG:
923 self.update_defconfig()
924 else:
Simon Glassdaa694d2021-12-18 14:54:30 -0700925 sys.exit('Internal Error. This should not happen.')
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900926
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900927 return True if self.state == STATE_IDLE else False
Joe Hershberger96464ba2015-05-19 13:21:17 -0500928
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900929 def handle_error(self):
930 """Handle error cases."""
Masahiro Yamada8513dc02016-05-19 15:52:08 +0900931
Simon Glassb2e83c62021-12-18 14:54:31 -0700932 self.log += color_text(self.args.color, COLOR_LIGHT_RED,
Simon Glassdaa694d2021-12-18 14:54:30 -0700933 'Failed to process.\n')
Simon Glassb2e83c62021-12-18 14:54:31 -0700934 if self.args.verbose:
935 self.log += color_text(self.args.color, COLOR_LIGHT_CYAN,
Markus Klotzbuecher4f5c5e92020-02-12 20:46:45 +0100936 self.ps.stderr.read().decode())
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900937 self.finish(False)
Joe Hershberger96464ba2015-05-19 13:21:17 -0500938
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900939 def do_defconfig(self):
940 """Run 'make <board>_defconfig' to create the .config file."""
Masahiro Yamadac8e1b102016-05-19 15:52:07 +0900941
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900942 cmd = list(self.make_cmd)
943 cmd.append(self.defconfig)
944 self.ps = subprocess.Popen(cmd, stdout=self.devnull,
Masahiro Yamadaf432c332016-06-15 14:33:52 +0900945 stderr=subprocess.PIPE,
946 cwd=self.current_src_dir)
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900947 self.state = STATE_DEFCONFIG
Masahiro Yamadac8e1b102016-05-19 15:52:07 +0900948
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900949 def do_autoconf(self):
Simon Glassf3b8e642017-06-01 19:39:01 -0600950 """Run 'make AUTO_CONF_PATH'."""
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900951
Simon Glass6821a742017-07-10 14:47:47 -0600952 arch = self.parser.get_arch()
953 try:
954 toolchain = self.toolchains.Select(arch)
955 except ValueError:
Simon Glassb2e83c62021-12-18 14:54:31 -0700956 self.log += color_text(self.args.color, COLOR_YELLOW,
Chris Packhamce3ba452017-08-27 20:00:51 +1200957 "Tool chain for '%s' is missing. Do nothing.\n" % arch)
Masahiro Yamada4efef992016-05-19 15:52:03 +0900958 self.finish(False)
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900959 return
Simon Glass793dca32019-10-31 07:42:57 -0600960 env = toolchain.MakeEnvironment(False)
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +0900961
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900962 cmd = list(self.make_cmd)
Joe Hershberger7740f652015-05-19 13:21:18 -0500963 cmd.append('KCONFIG_IGNORE_DUPLICATES=1')
Simon Glassf3b8e642017-06-01 19:39:01 -0600964 cmd.append(AUTO_CONF_PATH)
Simon Glass6821a742017-07-10 14:47:47 -0600965 self.ps = subprocess.Popen(cmd, stdout=self.devnull, env=env,
Masahiro Yamadaf432c332016-06-15 14:33:52 +0900966 stderr=subprocess.PIPE,
967 cwd=self.current_src_dir)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900968 self.state = STATE_AUTOCONF
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900969
Simon Glassd73fcb12017-06-01 19:39:02 -0600970 def do_build_db(self):
971 """Add the board to the database"""
972 configs = {}
973 with open(os.path.join(self.build_dir, AUTO_CONF_PATH)) as fd:
974 for line in fd.readlines():
975 if line.startswith('CONFIG'):
976 config, value = line.split('=', 1)
977 configs[config] = value.rstrip()
978 self.db_queue.put([self.defconfig, configs])
979 self.finish(True)
980
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900981 def do_savedefconfig(self):
982 """Update the .config and run 'make savedefconfig'."""
983
Masahiro Yamada916224c2016-08-22 22:18:21 +0900984 (updated, suspicious, log) = self.parser.update_dotconfig()
985 if suspicious:
986 self.suspicious_boards.add(self.defconfig)
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900987 self.log += log
988
Simon Glassb2e83c62021-12-18 14:54:31 -0700989 if not self.args.force_sync and not updated:
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900990 self.finish(True)
991 return
992 if updated:
Simon Glassb2e83c62021-12-18 14:54:31 -0700993 self.log += color_text(self.args.color, COLOR_LIGHT_GREEN,
Simon Glassdaa694d2021-12-18 14:54:30 -0700994 'Syncing by savedefconfig...\n')
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900995 else:
Simon Glassdaa694d2021-12-18 14:54:30 -0700996 self.log += 'Syncing by savedefconfig (forced by option)...\n'
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900997
998 cmd = list(self.make_cmd)
999 cmd.append('savedefconfig')
1000 self.ps = subprocess.Popen(cmd, stdout=self.devnull,
1001 stderr=subprocess.PIPE)
1002 self.state = STATE_SAVEDEFCONFIG
1003
1004 def update_defconfig(self):
1005 """Update the input defconfig and go back to the idle state."""
1006
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001007 log = self.parser.check_defconfig()
1008 if log:
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001009 self.suspicious_boards.add(self.defconfig)
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001010 self.log += log
Masahiro Yamadae307fa92016-06-08 11:47:37 +09001011 orig_defconfig = os.path.join('configs', self.defconfig)
1012 new_defconfig = os.path.join(self.build_dir, 'defconfig')
1013 updated = not filecmp.cmp(orig_defconfig, new_defconfig)
1014
1015 if updated:
Simon Glassb2e83c62021-12-18 14:54:31 -07001016 self.log += color_text(self.args.color, COLOR_LIGHT_BLUE,
Simon Glassdaa694d2021-12-18 14:54:30 -07001017 'defconfig was updated.\n')
Masahiro Yamadae307fa92016-06-08 11:47:37 +09001018
Simon Glassb2e83c62021-12-18 14:54:31 -07001019 if not self.args.dry_run and updated:
Masahiro Yamadae307fa92016-06-08 11:47:37 +09001020 shutil.move(new_defconfig, orig_defconfig)
1021 self.finish(True)
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001022
Masahiro Yamada4efef992016-05-19 15:52:03 +09001023 def finish(self, success):
1024 """Display log along with progress and go to the idle state.
Masahiro Yamada1d085562016-05-19 15:52:02 +09001025
1026 Arguments:
Masahiro Yamada4efef992016-05-19 15:52:03 +09001027 success: Should be True when the defconfig was processed
1028 successfully, or False when it fails.
Masahiro Yamada1d085562016-05-19 15:52:02 +09001029 """
1030 # output at least 30 characters to hide the "* defconfigs out of *".
1031 log = self.defconfig.ljust(30) + '\n'
1032
1033 log += '\n'.join([ ' ' + s for s in self.log.split('\n') ])
1034 # Some threads are running in parallel.
1035 # Print log atomically to not mix up logs from different threads.
Simon Glass793dca32019-10-31 07:42:57 -06001036 print(log, file=(sys.stdout if success else sys.stderr))
Masahiro Yamada4efef992016-05-19 15:52:03 +09001037
1038 if not success:
Simon Glassb2e83c62021-12-18 14:54:31 -07001039 if self.args.exit_on_error:
Simon Glassdaa694d2021-12-18 14:54:30 -07001040 sys.exit('Exit on error.')
Masahiro Yamada4efef992016-05-19 15:52:03 +09001041 # If --exit-on-error flag is not set, skip this board and continue.
1042 # Record the failed board.
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001043 self.failed_boards.add(self.defconfig)
Masahiro Yamada4efef992016-05-19 15:52:03 +09001044
Masahiro Yamada1d085562016-05-19 15:52:02 +09001045 self.progress.inc()
1046 self.progress.show()
Masahiro Yamada4efef992016-05-19 15:52:03 +09001047 self.state = STATE_IDLE
Masahiro Yamada1d085562016-05-19 15:52:02 +09001048
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001049 def get_failed_boards(self):
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001050 """Returns a set of failed boards (defconfigs) in this slot.
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001051 """
1052 return self.failed_boards
1053
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001054 def get_suspicious_boards(self):
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001055 """Returns a set of boards (defconfigs) with possible misconversion.
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001056 """
Masahiro Yamada916224c2016-08-22 22:18:21 +09001057 return self.suspicious_boards - self.failed_boards
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001058
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001059class Slots:
1060
1061 """Controller of the array of subprocess slots."""
1062
Simon Glassb2e83c62021-12-18 14:54:31 -07001063 def __init__(self, toolchains, configs, args, progress,
Simon Glass6821a742017-07-10 14:47:47 -06001064 reference_src_dir, db_queue):
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001065 """Create a new slots controller.
1066
1067 Arguments:
Simon Glass6821a742017-07-10 14:47:47 -06001068 toolchains: Toolchains object containing toolchains.
Masahiro Yamadab134bc12016-05-19 15:51:57 +09001069 configs: A list of CONFIGs to move.
Simon Glassb2e83c62021-12-18 14:54:31 -07001070 args: Program arguments
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +09001071 progress: A progress indicator.
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001072 reference_src_dir: Determine the true starting config state from this
1073 source tree.
Simon Glassd73fcb12017-06-01 19:39:02 -06001074 db_queue: output queue to write config info for the database
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001075 """
Simon Glassb2e83c62021-12-18 14:54:31 -07001076 self.args = args
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001077 self.slots = []
Simon Glass478920d2021-12-18 14:54:32 -07001078 devnull = subprocess.DEVNULL
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001079 make_cmd = get_make_cmd()
Simon Glassb2e83c62021-12-18 14:54:31 -07001080 for i in range(args.jobs):
1081 self.slots.append(Slot(toolchains, configs, args, progress,
Simon Glass6821a742017-07-10 14:47:47 -06001082 devnull, make_cmd, reference_src_dir,
1083 db_queue))
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001084
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +09001085 def add(self, defconfig):
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001086 """Add a new subprocess if a vacant slot is found.
1087
1088 Arguments:
1089 defconfig: defconfig name to be put into.
1090
1091 Returns:
1092 Return True on success or False on failure
1093 """
1094 for slot in self.slots:
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +09001095 if slot.add(defconfig):
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001096 return True
1097 return False
1098
1099 def available(self):
1100 """Check if there is a vacant slot.
1101
1102 Returns:
1103 Return True if at lease one vacant slot is found, False otherwise.
1104 """
1105 for slot in self.slots:
1106 if slot.poll():
1107 return True
1108 return False
1109
1110 def empty(self):
1111 """Check if all slots are vacant.
1112
1113 Returns:
1114 Return True if all the slots are vacant, False otherwise.
1115 """
1116 ret = True
1117 for slot in self.slots:
1118 if not slot.poll():
1119 ret = False
1120 return ret
1121
1122 def show_failed_boards(self):
1123 """Display all of the failed boards (defconfigs)."""
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001124 boards = set()
Masahiro Yamada96dccd92016-06-15 14:33:53 +09001125 output_file = 'moveconfig.failed'
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001126
1127 for slot in self.slots:
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001128 boards |= slot.get_failed_boards()
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001129
Masahiro Yamada96dccd92016-06-15 14:33:53 +09001130 if boards:
1131 boards = '\n'.join(boards) + '\n'
Simon Glassdaa694d2021-12-18 14:54:30 -07001132 msg = 'The following boards were not processed due to error:\n'
Masahiro Yamada96dccd92016-06-15 14:33:53 +09001133 msg += boards
Simon Glassdaa694d2021-12-18 14:54:30 -07001134 msg += '(the list has been saved in %s)\n' % output_file
Simon Glassb2e83c62021-12-18 14:54:31 -07001135 print(color_text(self.args.color, COLOR_LIGHT_RED,
Simon Glass793dca32019-10-31 07:42:57 -06001136 msg), file=sys.stderr)
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001137
Masahiro Yamada96dccd92016-06-15 14:33:53 +09001138 with open(output_file, 'w') as f:
1139 f.write(boards)
Joe Hershberger2559cd82015-05-19 13:21:22 -05001140
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001141 def show_suspicious_boards(self):
1142 """Display all boards (defconfigs) with possible misconversion."""
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001143 boards = set()
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001144 output_file = 'moveconfig.suspicious'
1145
1146 for slot in self.slots:
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001147 boards |= slot.get_suspicious_boards()
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001148
1149 if boards:
1150 boards = '\n'.join(boards) + '\n'
Simon Glassdaa694d2021-12-18 14:54:30 -07001151 msg = 'The following boards might have been converted incorrectly.\n'
1152 msg += 'It is highly recommended to check them manually:\n'
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001153 msg += boards
Simon Glassdaa694d2021-12-18 14:54:30 -07001154 msg += '(the list has been saved in %s)\n' % output_file
Simon Glassb2e83c62021-12-18 14:54:31 -07001155 print(color_text(self.args.color, COLOR_YELLOW,
Simon Glass793dca32019-10-31 07:42:57 -06001156 msg), file=sys.stderr)
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001157
1158 with open(output_file, 'w') as f:
1159 f.write(boards)
1160
Masahiro Yamada5cc42a52016-06-15 14:33:51 +09001161class ReferenceSource:
1162
1163 """Reference source against which original configs should be parsed."""
1164
1165 def __init__(self, commit):
1166 """Create a reference source directory based on a specified commit.
1167
1168 Arguments:
1169 commit: commit to git-clone
1170 """
1171 self.src_dir = tempfile.mkdtemp()
Simon Glassdaa694d2021-12-18 14:54:30 -07001172 print('Cloning git repo to a separate work directory...')
Masahiro Yamada5cc42a52016-06-15 14:33:51 +09001173 subprocess.check_output(['git', 'clone', os.getcwd(), '.'],
1174 cwd=self.src_dir)
Simon Glass793dca32019-10-31 07:42:57 -06001175 print("Checkout '%s' to build the original autoconf.mk." % \
1176 subprocess.check_output(['git', 'rev-parse', '--short', commit]).strip())
Masahiro Yamada5cc42a52016-06-15 14:33:51 +09001177 subprocess.check_output(['git', 'checkout', commit],
1178 stderr=subprocess.STDOUT, cwd=self.src_dir)
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001179
1180 def __del__(self):
Masahiro Yamada5cc42a52016-06-15 14:33:51 +09001181 """Delete the reference source directory
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001182
1183 This function makes sure the temporary directory is cleaned away
1184 even if Python suddenly dies due to error. It should be done in here
1185 because it is guaranteed the destructor is always invoked when the
1186 instance of the class gets unreferenced.
1187 """
Masahiro Yamada5cc42a52016-06-15 14:33:51 +09001188 shutil.rmtree(self.src_dir)
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001189
Masahiro Yamada5cc42a52016-06-15 14:33:51 +09001190 def get_dir(self):
1191 """Return the absolute path to the reference source directory."""
1192
1193 return self.src_dir
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001194
Simon Glassb2e83c62021-12-18 14:54:31 -07001195def move_config(toolchains, configs, args, db_queue):
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001196 """Move config options to defconfig files.
1197
1198 Arguments:
Masahiro Yamadab134bc12016-05-19 15:51:57 +09001199 configs: A list of CONFIGs to move.
Simon Glassb2e83c62021-12-18 14:54:31 -07001200 args: Program arguments
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001201 """
Masahiro Yamadab134bc12016-05-19 15:51:57 +09001202 if len(configs) == 0:
Simon Glassb2e83c62021-12-18 14:54:31 -07001203 if args.force_sync:
Simon Glass793dca32019-10-31 07:42:57 -06001204 print('No CONFIG is specified. You are probably syncing defconfigs.', end=' ')
Simon Glassb2e83c62021-12-18 14:54:31 -07001205 elif args.build_db:
Simon Glass793dca32019-10-31 07:42:57 -06001206 print('Building %s database' % CONFIG_DATABASE)
Masahiro Yamada6a9f79f2016-05-19 15:52:09 +09001207 else:
Simon Glass793dca32019-10-31 07:42:57 -06001208 print('Neither CONFIG nor --force-sync is specified. Nothing will happen.', end=' ')
Masahiro Yamada6a9f79f2016-05-19 15:52:09 +09001209 else:
Simon Glass793dca32019-10-31 07:42:57 -06001210 print('Move ' + ', '.join(configs), end=' ')
Simon Glassb2e83c62021-12-18 14:54:31 -07001211 print('(jobs: %d)\n' % args.jobs)
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001212
Simon Glassb2e83c62021-12-18 14:54:31 -07001213 if args.git_ref:
1214 reference_src = ReferenceSource(args.git_ref)
Masahiro Yamada5cc42a52016-06-15 14:33:51 +09001215 reference_src_dir = reference_src.get_dir()
1216 else:
Masahiro Yamadaf432c332016-06-15 14:33:52 +09001217 reference_src_dir = None
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001218
Simon Glassb2e83c62021-12-18 14:54:31 -07001219 if args.defconfigs:
1220 defconfigs = get_matched_defconfigs(args.defconfigs)
Joe Hershberger91040e82015-05-19 13:21:19 -05001221 else:
Masahiro Yamada684c3062016-07-25 19:15:28 +09001222 defconfigs = get_all_defconfigs()
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001223
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +09001224 progress = Progress(len(defconfigs))
Simon Glassb2e83c62021-12-18 14:54:31 -07001225 slots = Slots(toolchains, configs, args, progress, reference_src_dir,
Simon Glass6821a742017-07-10 14:47:47 -06001226 db_queue)
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001227
1228 # Main loop to process defconfig files:
1229 # Add a new subprocess into a vacant slot.
1230 # Sleep if there is no available slot.
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +09001231 for defconfig in defconfigs:
1232 while not slots.add(defconfig):
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001233 while not slots.available():
1234 # No available slot: sleep for a while
1235 time.sleep(SLEEP_TIME)
1236
1237 # wait until all the subprocesses finish
1238 while not slots.empty():
1239 time.sleep(SLEEP_TIME)
1240
Simon Glass793dca32019-10-31 07:42:57 -06001241 print('')
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001242 slots.show_failed_boards()
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001243 slots.show_suspicious_boards()
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001244
Simon Glasscb008832017-06-15 21:39:33 -06001245def find_kconfig_rules(kconf, config, imply_config):
1246 """Check whether a config has a 'select' or 'imply' keyword
1247
1248 Args:
Tom Rini65e05dd2019-09-20 17:42:09 -04001249 kconf: Kconfiglib.Kconfig object
Simon Glasscb008832017-06-15 21:39:33 -06001250 config: Name of config to check (without CONFIG_ prefix)
1251 imply_config: Implying config (without CONFIG_ prefix) which may or
1252 may not have an 'imply' for 'config')
1253
1254 Returns:
1255 Symbol object for 'config' if found, else None
1256 """
Tom Rini65e05dd2019-09-20 17:42:09 -04001257 sym = kconf.syms.get(imply_config)
Simon Glasscb008832017-06-15 21:39:33 -06001258 if sym:
Simon Glassea40b202021-07-21 21:35:53 -06001259 for sel, cond in (sym.selects + sym.implies):
Simon Glassa3627082021-12-18 08:09:42 -07001260 if sel.name == config:
Simon Glasscb008832017-06-15 21:39:33 -06001261 return sym
1262 return None
1263
1264def check_imply_rule(kconf, config, imply_config):
1265 """Check if we can add an 'imply' option
1266
1267 This finds imply_config in the Kconfig and looks to see if it is possible
1268 to add an 'imply' for 'config' to that part of the Kconfig.
1269
1270 Args:
Tom Rini65e05dd2019-09-20 17:42:09 -04001271 kconf: Kconfiglib.Kconfig object
Simon Glasscb008832017-06-15 21:39:33 -06001272 config: Name of config to check (without CONFIG_ prefix)
1273 imply_config: Implying config (without CONFIG_ prefix) which may or
1274 may not have an 'imply' for 'config')
1275
1276 Returns:
1277 tuple:
1278 filename of Kconfig file containing imply_config, or None if none
1279 line number within the Kconfig file, or 0 if none
1280 message indicating the result
1281 """
Tom Rini65e05dd2019-09-20 17:42:09 -04001282 sym = kconf.syms.get(imply_config)
Simon Glasscb008832017-06-15 21:39:33 -06001283 if not sym:
1284 return 'cannot find sym'
Simon Glassea40b202021-07-21 21:35:53 -06001285 nodes = sym.nodes
1286 if len(nodes) != 1:
1287 return '%d locations' % len(nodes)
Simon Glassa3627082021-12-18 08:09:42 -07001288 node = nodes[0]
1289 fname, linenum = node.filename, node.linenr
Simon Glasscb008832017-06-15 21:39:33 -06001290 cwd = os.getcwd()
1291 if cwd and fname.startswith(cwd):
1292 fname = fname[len(cwd) + 1:]
1293 file_line = ' at %s:%d' % (fname, linenum)
1294 with open(fname) as fd:
1295 data = fd.read().splitlines()
1296 if data[linenum - 1] != 'config %s' % imply_config:
1297 return None, 0, 'bad sym format %s%s' % (data[linenum], file_line)
1298 return fname, linenum, 'adding%s' % file_line
1299
1300def add_imply_rule(config, fname, linenum):
1301 """Add a new 'imply' option to a Kconfig
1302
1303 Args:
1304 config: config option to add an imply for (without CONFIG_ prefix)
1305 fname: Kconfig filename to update
1306 linenum: Line number to place the 'imply' before
1307
1308 Returns:
1309 Message indicating the result
1310 """
1311 file_line = ' at %s:%d' % (fname, linenum)
1312 data = open(fname).read().splitlines()
1313 linenum -= 1
1314
1315 for offset, line in enumerate(data[linenum:]):
1316 if line.strip().startswith('help') or not line:
1317 data.insert(linenum + offset, '\timply %s' % config)
1318 with open(fname, 'w') as fd:
1319 fd.write('\n'.join(data) + '\n')
1320 return 'added%s' % file_line
1321
1322 return 'could not insert%s'
1323
1324(IMPLY_MIN_2, IMPLY_TARGET, IMPLY_CMD, IMPLY_NON_ARCH_BOARD) = (
1325 1, 2, 4, 8)
Simon Glass9b2a2e82017-06-15 21:39:32 -06001326
1327IMPLY_FLAGS = {
1328 'min2': [IMPLY_MIN_2, 'Show options which imply >2 boards (normally >5)'],
1329 'target': [IMPLY_TARGET, 'Allow CONFIG_TARGET_... options to imply'],
1330 'cmd': [IMPLY_CMD, 'Allow CONFIG_CMD_... to imply'],
Simon Glasscb008832017-06-15 21:39:33 -06001331 'non-arch-board': [
1332 IMPLY_NON_ARCH_BOARD,
1333 'Allow Kconfig options outside arch/ and /board/ to imply'],
Simon Glass9b2a2e82017-06-15 21:39:32 -06001334};
1335
Simon Glass9d603392021-12-18 08:09:43 -07001336
1337def read_database():
1338 """Read in the config database
1339
1340 Returns:
1341 tuple:
1342 set of all config options seen (each a str)
1343 set of all defconfigs seen (each a str)
1344 dict of configs for each defconfig:
1345 key: defconfig name, e.g. "MPC8548CDS_legacy_defconfig"
1346 value: dict:
1347 key: CONFIG option
1348 value: Value of option
1349 dict of defconfigs for each config:
1350 key: CONFIG option
1351 value: set of boards using that option
1352
1353 """
1354 configs = {}
1355
1356 # key is defconfig name, value is dict of (CONFIG_xxx, value)
1357 config_db = {}
1358
1359 # Set of all config options we have seen
1360 all_configs = set()
1361
1362 # Set of all defconfigs we have seen
1363 all_defconfigs = set()
1364
1365 defconfig_db = collections.defaultdict(set)
1366 with open(CONFIG_DATABASE) as fd:
1367 for line in fd.readlines():
1368 line = line.rstrip()
1369 if not line: # Separator between defconfigs
1370 config_db[defconfig] = configs
1371 all_defconfigs.add(defconfig)
1372 configs = {}
1373 elif line[0] == ' ': # CONFIG line
1374 config, value = line.strip().split('=', 1)
1375 configs[config] = value
1376 defconfig_db[config].add(defconfig)
1377 all_configs.add(config)
1378 else: # New defconfig
1379 defconfig = line
1380
1381 return all_configs, all_defconfigs, config_db, defconfig_db
1382
1383
Simon Glasscb008832017-06-15 21:39:33 -06001384def do_imply_config(config_list, add_imply, imply_flags, skip_added,
1385 check_kconfig=True, find_superset=False):
Simon Glass99b66602017-06-01 19:39:03 -06001386 """Find CONFIG options which imply those in the list
1387
1388 Some CONFIG options can be implied by others and this can help to reduce
1389 the size of the defconfig files. For example, CONFIG_X86 implies
1390 CONFIG_CMD_IRQ, so we can put 'imply CMD_IRQ' under 'config X86' and
1391 all x86 boards will have that option, avoiding adding CONFIG_CMD_IRQ to
1392 each of the x86 defconfig files.
1393
1394 This function uses the moveconfig database to find such options. It
1395 displays a list of things that could possibly imply those in the list.
1396 The algorithm ignores any that start with CONFIG_TARGET since these
1397 typically refer to only a few defconfigs (often one). It also does not
1398 display a config with less than 5 defconfigs.
1399
1400 The algorithm works using sets. For each target config in config_list:
1401 - Get the set 'defconfigs' which use that target config
1402 - For each config (from a list of all configs):
1403 - Get the set 'imply_defconfig' of defconfigs which use that config
1404 -
1405 - If imply_defconfigs contains anything not in defconfigs then
1406 this config does not imply the target config
1407
1408 Params:
1409 config_list: List of CONFIG options to check (each a string)
Simon Glasscb008832017-06-15 21:39:33 -06001410 add_imply: Automatically add an 'imply' for each config.
Simon Glass9b2a2e82017-06-15 21:39:32 -06001411 imply_flags: Flags which control which implying configs are allowed
1412 (IMPLY_...)
Simon Glasscb008832017-06-15 21:39:33 -06001413 skip_added: Don't show options which already have an imply added.
1414 check_kconfig: Check if implied symbols already have an 'imply' or
1415 'select' for the target config, and show this information if so.
Simon Glass99b66602017-06-01 19:39:03 -06001416 find_superset: True to look for configs which are a superset of those
1417 already found. So for example if CONFIG_EXYNOS5 implies an option,
1418 but CONFIG_EXYNOS covers a larger set of defconfigs and also
1419 implies that option, this will drop the former in favour of the
1420 latter. In practice this option has not proved very used.
1421
1422 Note the terminoloy:
1423 config - a CONFIG_XXX options (a string, e.g. 'CONFIG_CMD_EEPROM')
1424 defconfig - a defconfig file (a string, e.g. 'configs/snow_defconfig')
1425 """
Simon Glasscb008832017-06-15 21:39:33 -06001426 kconf = KconfigScanner().conf if check_kconfig else None
1427 if add_imply and add_imply != 'all':
Simon Glassa3627082021-12-18 08:09:42 -07001428 add_imply = add_imply.split(',')
Simon Glasscb008832017-06-15 21:39:33 -06001429
Simon Glass9d603392021-12-18 08:09:43 -07001430 all_configs, all_defconfigs, config_db, defconfig_db = read_database()
Simon Glass99b66602017-06-01 19:39:03 -06001431
Simon Glassa3627082021-12-18 08:09:42 -07001432 # Work through each target config option in turn, independently
Simon Glass99b66602017-06-01 19:39:03 -06001433 for config in config_list:
1434 defconfigs = defconfig_db.get(config)
1435 if not defconfigs:
Simon Glass793dca32019-10-31 07:42:57 -06001436 print('%s not found in any defconfig' % config)
Simon Glass99b66602017-06-01 19:39:03 -06001437 continue
1438
1439 # Get the set of defconfigs without this one (since a config cannot
1440 # imply itself)
1441 non_defconfigs = all_defconfigs - defconfigs
1442 num_defconfigs = len(defconfigs)
Simon Glass793dca32019-10-31 07:42:57 -06001443 print('%s found in %d/%d defconfigs' % (config, num_defconfigs,
1444 len(all_configs)))
Simon Glass99b66602017-06-01 19:39:03 -06001445
1446 # This will hold the results: key=config, value=defconfigs containing it
1447 imply_configs = {}
1448 rest_configs = all_configs - set([config])
1449
1450 # Look at every possible config, except the target one
1451 for imply_config in rest_configs:
Simon Glass9b2a2e82017-06-15 21:39:32 -06001452 if 'ERRATUM' in imply_config:
Simon Glass99b66602017-06-01 19:39:03 -06001453 continue
Simon Glass9b2a2e82017-06-15 21:39:32 -06001454 if not (imply_flags & IMPLY_CMD):
1455 if 'CONFIG_CMD' in imply_config:
1456 continue
1457 if not (imply_flags & IMPLY_TARGET):
1458 if 'CONFIG_TARGET' in imply_config:
1459 continue
Simon Glass99b66602017-06-01 19:39:03 -06001460
1461 # Find set of defconfigs that have this config
1462 imply_defconfig = defconfig_db[imply_config]
1463
1464 # Get the intersection of this with defconfigs containing the
1465 # target config
1466 common_defconfigs = imply_defconfig & defconfigs
1467
1468 # Get the set of defconfigs containing this config which DO NOT
1469 # also contain the taret config. If this set is non-empty it means
1470 # that this config affects other defconfigs as well as (possibly)
1471 # the ones affected by the target config. This means it implies
1472 # things we don't want to imply.
1473 not_common_defconfigs = imply_defconfig & non_defconfigs
1474 if not_common_defconfigs:
1475 continue
1476
1477 # If there are common defconfigs, imply_config may be useful
1478 if common_defconfigs:
1479 skip = False
1480 if find_superset:
Simon Glass793dca32019-10-31 07:42:57 -06001481 for prev in list(imply_configs.keys()):
Simon Glass99b66602017-06-01 19:39:03 -06001482 prev_count = len(imply_configs[prev])
1483 count = len(common_defconfigs)
1484 if (prev_count > count and
1485 (imply_configs[prev] & common_defconfigs ==
1486 common_defconfigs)):
1487 # skip imply_config because prev is a superset
1488 skip = True
1489 break
1490 elif count > prev_count:
1491 # delete prev because imply_config is a superset
1492 del imply_configs[prev]
1493 if not skip:
1494 imply_configs[imply_config] = common_defconfigs
1495
1496 # Now we have a dict imply_configs of configs which imply each config
1497 # The value of each dict item is the set of defconfigs containing that
1498 # config. Rank them so that we print the configs that imply the largest
1499 # number of defconfigs first.
Simon Glasscb008832017-06-15 21:39:33 -06001500 ranked_iconfigs = sorted(imply_configs,
Simon Glass99b66602017-06-01 19:39:03 -06001501 key=lambda k: len(imply_configs[k]), reverse=True)
Simon Glasscb008832017-06-15 21:39:33 -06001502 kconfig_info = ''
1503 cwd = os.getcwd()
1504 add_list = collections.defaultdict(list)
1505 for iconfig in ranked_iconfigs:
1506 num_common = len(imply_configs[iconfig])
Simon Glass99b66602017-06-01 19:39:03 -06001507
1508 # Don't bother if there are less than 5 defconfigs affected.
Simon Glass9b2a2e82017-06-15 21:39:32 -06001509 if num_common < (2 if imply_flags & IMPLY_MIN_2 else 5):
Simon Glass99b66602017-06-01 19:39:03 -06001510 continue
Simon Glasscb008832017-06-15 21:39:33 -06001511 missing = defconfigs - imply_configs[iconfig]
Simon Glass99b66602017-06-01 19:39:03 -06001512 missing_str = ', '.join(missing) if missing else 'all'
1513 missing_str = ''
Simon Glasscb008832017-06-15 21:39:33 -06001514 show = True
1515 if kconf:
1516 sym = find_kconfig_rules(kconf, config[CONFIG_LEN:],
1517 iconfig[CONFIG_LEN:])
1518 kconfig_info = ''
1519 if sym:
Simon Glassea40b202021-07-21 21:35:53 -06001520 nodes = sym.nodes
1521 if len(nodes) == 1:
1522 fname, linenum = nodes[0].filename, nodes[0].linenr
Simon Glasscb008832017-06-15 21:39:33 -06001523 if cwd and fname.startswith(cwd):
1524 fname = fname[len(cwd) + 1:]
1525 kconfig_info = '%s:%d' % (fname, linenum)
1526 if skip_added:
1527 show = False
1528 else:
Tom Rini65e05dd2019-09-20 17:42:09 -04001529 sym = kconf.syms.get(iconfig[CONFIG_LEN:])
Simon Glasscb008832017-06-15 21:39:33 -06001530 fname = ''
1531 if sym:
Simon Glassea40b202021-07-21 21:35:53 -06001532 nodes = sym.nodes
1533 if len(nodes) == 1:
1534 fname, linenum = nodes[0].filename, nodes[0].linenr
Simon Glasscb008832017-06-15 21:39:33 -06001535 if cwd and fname.startswith(cwd):
1536 fname = fname[len(cwd) + 1:]
1537 in_arch_board = not sym or (fname.startswith('arch') or
1538 fname.startswith('board'))
1539 if (not in_arch_board and
1540 not (imply_flags & IMPLY_NON_ARCH_BOARD)):
1541 continue
1542
1543 if add_imply and (add_imply == 'all' or
1544 iconfig in add_imply):
1545 fname, linenum, kconfig_info = (check_imply_rule(kconf,
1546 config[CONFIG_LEN:], iconfig[CONFIG_LEN:]))
1547 if fname:
1548 add_list[fname].append(linenum)
1549
1550 if show and kconfig_info != 'skip':
Simon Glass793dca32019-10-31 07:42:57 -06001551 print('%5d : %-30s%-25s %s' % (num_common, iconfig.ljust(30),
1552 kconfig_info, missing_str))
Simon Glasscb008832017-06-15 21:39:33 -06001553
1554 # Having collected a list of things to add, now we add them. We process
1555 # each file from the largest line number to the smallest so that
1556 # earlier additions do not affect our line numbers. E.g. if we added an
1557 # imply at line 20 it would change the position of each line after
1558 # that.
Simon Glass793dca32019-10-31 07:42:57 -06001559 for fname, linenums in add_list.items():
Simon Glasscb008832017-06-15 21:39:33 -06001560 for linenum in sorted(linenums, reverse=True):
1561 add_imply_rule(config[CONFIG_LEN:], fname, linenum)
Simon Glass99b66602017-06-01 19:39:03 -06001562
1563
Simon Glass65d7fce2021-12-18 08:09:46 -07001564def do_find_config(config_list):
1565 """Find boards with a given combination of CONFIGs
1566
1567 Params:
1568 config_list: List of CONFIG options to check (each a string consisting
1569 of a config option, with or without a CONFIG_ prefix. If an option
1570 is preceded by a tilde (~) then it must be false, otherwise it must
1571 be true)
1572 """
1573 all_configs, all_defconfigs, config_db, defconfig_db = read_database()
1574
1575 # Get the whitelist
1576 with open('scripts/config_whitelist.txt') as inf:
1577 adhoc_configs = set(inf.read().splitlines())
1578
1579 # Start with all defconfigs
1580 out = all_defconfigs
1581
1582 # Work through each config in turn
1583 adhoc = []
1584 for item in config_list:
1585 # Get the real config name and whether we want this config or not
1586 cfg = item
1587 want = True
1588 if cfg[0] == '~':
1589 want = False
1590 cfg = cfg[1:]
1591
1592 if cfg in adhoc_configs:
1593 adhoc.append(cfg)
1594 continue
1595
1596 # Search everything that is still in the running. If it has a config
1597 # that we want, or doesn't have one that we don't, add it into the
1598 # running for the next stage
1599 in_list = out
1600 out = set()
1601 for defc in in_list:
1602 has_cfg = cfg in config_db[defc]
1603 if has_cfg == want:
1604 out.add(defc)
1605 if adhoc:
1606 print(f"Error: Not in Kconfig: %s" % ' '.join(adhoc))
1607 else:
1608 print(f'{len(out)} matches')
1609 print(' '.join(out))
1610
1611
1612def prefix_config(cfg):
1613 """Prefix a config with CONFIG_ if needed
1614
1615 This handles ~ operator, which indicates that the CONFIG should be disabled
1616
1617 >>> prefix_config('FRED')
1618 'CONFIG_FRED'
1619 >>> prefix_config('CONFIG_FRED')
1620 'CONFIG_FRED'
1621 >>> prefix_config('~FRED')
1622 '~CONFIG_FRED'
1623 >>> prefix_config('~CONFIG_FRED')
1624 '~CONFIG_FRED'
1625 >>> prefix_config('A123')
1626 'CONFIG_A123'
1627 """
1628 op = ''
1629 if cfg[0] == '~':
1630 op = cfg[0]
1631 cfg = cfg[1:]
1632 if not cfg.startswith('CONFIG_'):
1633 cfg = 'CONFIG_' + cfg
1634 return op + cfg
1635
1636
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001637def main():
1638 try:
1639 cpu_count = multiprocessing.cpu_count()
1640 except NotImplementedError:
1641 cpu_count = 1
1642
Simon Glassb2e83c62021-12-18 14:54:31 -07001643 epilog = '''Move config options from headers to defconfig files. See
1644doc/develop/moveconfig.rst for documentation.'''
1645
1646 parser = ArgumentParser(epilog=epilog)
1647 # Add arguments here
1648 parser.add_argument('-a', '--add-imply', type=str, default='',
Simon Glasscb008832017-06-15 21:39:33 -06001649 help='comma-separated list of CONFIG options to add '
1650 "an 'imply' statement to for the CONFIG in -i")
Simon Glassb2e83c62021-12-18 14:54:31 -07001651 parser.add_argument('-A', '--skip-added', action='store_true', default=False,
Simon Glasscb008832017-06-15 21:39:33 -06001652 help="don't show options which are already marked as "
1653 'implying others')
Simon Glassb2e83c62021-12-18 14:54:31 -07001654 parser.add_argument('-b', '--build-db', action='store_true', default=False,
Simon Glassd73fcb12017-06-01 19:39:02 -06001655 help='build a CONFIG database')
Simon Glassb2e83c62021-12-18 14:54:31 -07001656 parser.add_argument('-c', '--color', action='store_true', default=False,
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001657 help='display the log in color')
Simon Glassb2e83c62021-12-18 14:54:31 -07001658 parser.add_argument('-C', '--commit', action='store_true', default=False,
Simon Glass9ede2122016-09-12 23:18:21 -06001659 help='Create a git commit for the operation')
Simon Glassb2e83c62021-12-18 14:54:31 -07001660 parser.add_argument('-d', '--defconfigs', type=str,
Simon Glassee4e61b2017-06-01 19:38:59 -06001661 help='a file containing a list of defconfigs to move, '
1662 "one per line (for example 'snow_defconfig') "
1663 "or '-' to read from stdin")
Simon Glassb2e83c62021-12-18 14:54:31 -07001664 parser.add_argument('-e', '--exit-on-error', action='store_true',
Simon Glasse1ae5632021-12-18 08:09:44 -07001665 default=False,
1666 help='exit immediately on any error')
Simon Glassb2e83c62021-12-18 14:54:31 -07001667 parser.add_argument('-f', '--find', action='store_true', default=False,
Simon Glass65d7fce2021-12-18 08:09:46 -07001668 help='Find boards with a given config combination')
Simon Glassb2e83c62021-12-18 14:54:31 -07001669 parser.add_argument('-H', '--headers-only', dest='cleanup_headers_only',
Simon Glasse1ae5632021-12-18 08:09:44 -07001670 action='store_true', default=False,
1671 help='only cleanup the headers')
Simon Glassb2e83c62021-12-18 14:54:31 -07001672 parser.add_argument('-i', '--imply', action='store_true', default=False,
Simon Glass99b66602017-06-01 19:39:03 -06001673 help='find options which imply others')
Simon Glassb2e83c62021-12-18 14:54:31 -07001674 parser.add_argument('-I', '--imply-flags', type=str, default='',
Simon Glass9b2a2e82017-06-15 21:39:32 -06001675 help="control the -i option ('help' for help")
Simon Glassb2e83c62021-12-18 14:54:31 -07001676 parser.add_argument('-j', '--jobs', type=int, default=cpu_count,
Simon Glasse1ae5632021-12-18 08:09:44 -07001677 help='the number of jobs to run simultaneously')
Simon Glassb2e83c62021-12-18 14:54:31 -07001678 parser.add_argument('-n', '--dry-run', action='store_true', default=False,
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001679 help='perform a trial run (show log with no changes)')
Simon Glassb2e83c62021-12-18 14:54:31 -07001680 parser.add_argument('-r', '--git-ref', type=str,
Simon Glasse1ae5632021-12-18 08:09:44 -07001681 help='the git ref to clone for building the autoconf.mk')
Simon Glassb2e83c62021-12-18 14:54:31 -07001682 parser.add_argument('-s', '--force-sync', action='store_true', default=False,
Masahiro Yamada8513dc02016-05-19 15:52:08 +09001683 help='force sync by savedefconfig')
Simon Glassb2e83c62021-12-18 14:54:31 -07001684 parser.add_argument('-S', '--spl', action='store_true', default=False,
Masahiro Yamada07913d12016-08-22 22:18:22 +09001685 help='parse config options defined for SPL build')
Simon Glassb2e83c62021-12-18 14:54:31 -07001686 parser.add_argument('-t', '--test', action='store_true', default=False,
Simon Glasse1ae5632021-12-18 08:09:44 -07001687 help='run unit tests')
Simon Glassb2e83c62021-12-18 14:54:31 -07001688 parser.add_argument('-y', '--yes', action='store_true', default=False,
Simon Glass6b403df2016-09-12 23:18:20 -06001689 help="respond 'yes' to any prompts")
Simon Glassb2e83c62021-12-18 14:54:31 -07001690 parser.add_argument('-v', '--verbose', action='store_true', default=False,
Joe Hershberger95bf9c72015-05-19 13:21:24 -05001691 help='show any build errors as boards are built')
Simon Glassb2e83c62021-12-18 14:54:31 -07001692 parser.add_argument('configs', nargs='*')
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001693
Simon Glassb2e83c62021-12-18 14:54:31 -07001694 args = parser.parse_args()
1695 configs = args.configs
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001696
Simon Glassb2e83c62021-12-18 14:54:31 -07001697 if args.test:
Simon Glass84067a52021-12-18 08:09:45 -07001698 sys.argv = [sys.argv[0]]
1699 fail, count = doctest.testmod()
1700 if fail:
1701 return 1
1702 unittest.main()
1703
Simon Glassb2e83c62021-12-18 14:54:31 -07001704 if not any((len(configs), args.force_sync, args.build_db, args.imply,
1705 args.find)):
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001706 parser.print_usage()
1707 sys.exit(1)
1708
Masahiro Yamadab6ef3932016-05-19 15:51:58 +09001709 # prefix the option name with CONFIG_ if missing
Simon Glass65d7fce2021-12-18 08:09:46 -07001710 configs = [prefix_config(cfg) for cfg in configs]
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001711
Joe Hershberger2144f882015-05-19 13:21:20 -05001712 check_top_directory()
1713
Simon Glassb2e83c62021-12-18 14:54:31 -07001714 if args.imply:
Simon Glass9b2a2e82017-06-15 21:39:32 -06001715 imply_flags = 0
Simon Glassb2e83c62021-12-18 14:54:31 -07001716 if args.imply_flags == 'all':
Simon Glassdee36c72017-07-10 14:47:46 -06001717 imply_flags = -1
1718
Simon Glassb2e83c62021-12-18 14:54:31 -07001719 elif args.imply_flags:
1720 for flag in args.imply_flags.split(','):
Simon Glassdee36c72017-07-10 14:47:46 -06001721 bad = flag not in IMPLY_FLAGS
1722 if bad:
Simon Glass793dca32019-10-31 07:42:57 -06001723 print("Invalid flag '%s'" % flag)
Simon Glassdee36c72017-07-10 14:47:46 -06001724 if flag == 'help' or bad:
Simon Glass793dca32019-10-31 07:42:57 -06001725 print("Imply flags: (separate with ',')")
1726 for name, info in IMPLY_FLAGS.items():
1727 print(' %-15s: %s' % (name, info[1]))
Simon Glassdee36c72017-07-10 14:47:46 -06001728 parser.print_usage()
1729 sys.exit(1)
1730 imply_flags |= IMPLY_FLAGS[flag][0]
Simon Glass9b2a2e82017-06-15 21:39:32 -06001731
Simon Glassb2e83c62021-12-18 14:54:31 -07001732 do_imply_config(configs, args.add_imply, imply_flags, args.skip_added)
Simon Glass99b66602017-06-01 19:39:03 -06001733 return
1734
Simon Glassb2e83c62021-12-18 14:54:31 -07001735 if args.find:
Simon Glass65d7fce2021-12-18 08:09:46 -07001736 do_find_config(configs)
1737 return
1738
Simon Glassd73fcb12017-06-01 19:39:02 -06001739 config_db = {}
Simon Glass793dca32019-10-31 07:42:57 -06001740 db_queue = queue.Queue()
Simon Glassd73fcb12017-06-01 19:39:02 -06001741 t = DatabaseThread(config_db, db_queue)
1742 t.setDaemon(True)
1743 t.start()
1744
Simon Glassb2e83c62021-12-18 14:54:31 -07001745 if not args.cleanup_headers_only:
Masahiro Yamadaf7536f72016-07-25 19:15:23 +09001746 check_clean_directory()
Simon Glass793dca32019-10-31 07:42:57 -06001747 bsettings.Setup('')
Simon Glass6821a742017-07-10 14:47:47 -06001748 toolchains = toolchain.Toolchains()
1749 toolchains.GetSettings()
1750 toolchains.Scan(verbose=False)
Simon Glassb2e83c62021-12-18 14:54:31 -07001751 move_config(toolchains, configs, args, db_queue)
Simon Glassd73fcb12017-06-01 19:39:02 -06001752 db_queue.join()
Joe Hershberger2144f882015-05-19 13:21:20 -05001753
Masahiro Yamada6a9f79f2016-05-19 15:52:09 +09001754 if configs:
Simon Glassb2e83c62021-12-18 14:54:31 -07001755 cleanup_headers(configs, args)
1756 cleanup_extra_options(configs, args)
1757 cleanup_whitelist(configs, args)
1758 cleanup_readme(configs, args)
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001759
Simon Glassb2e83c62021-12-18 14:54:31 -07001760 if args.commit:
Simon Glass9ede2122016-09-12 23:18:21 -06001761 subprocess.call(['git', 'add', '-u'])
1762 if configs:
1763 msg = 'Convert %s %sto Kconfig' % (configs[0],
1764 'et al ' if len(configs) > 1 else '')
1765 msg += ('\n\nThis converts the following to Kconfig:\n %s\n' %
1766 '\n '.join(configs))
1767 else:
1768 msg = 'configs: Resync with savedefconfig'
1769 msg += '\n\nRsync all defconfig files using moveconfig.py'
1770 subprocess.call(['git', 'commit', '-s', '-m', msg])
1771
Simon Glassb2e83c62021-12-18 14:54:31 -07001772 if args.build_db:
Simon Glassd73fcb12017-06-01 19:39:02 -06001773 with open(CONFIG_DATABASE, 'w') as fd:
Simon Glass793dca32019-10-31 07:42:57 -06001774 for defconfig, configs in config_db.items():
Simon Glassc79d18c2017-08-13 16:02:54 -06001775 fd.write('%s\n' % defconfig)
Simon Glassd73fcb12017-06-01 19:39:02 -06001776 for config in sorted(configs.keys()):
Simon Glassc79d18c2017-08-13 16:02:54 -06001777 fd.write(' %s=%s\n' % (config, configs[config]))
1778 fd.write('\n')
Simon Glassd73fcb12017-06-01 19:39:02 -06001779
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001780if __name__ == '__main__':
Simon Glass65d7fce2021-12-18 08:09:46 -07001781 sys.exit(main())