blob: 4932bd9b86f831c03d384f88bb54362b29b6f41d [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 Glass2fd85bd2021-12-18 14:54:33 -0700276def write_file(fname, data):
277 """Write data to a file
278
279 Args:
280 fname (str): Filename to write to
281 data (list of str): Lines to write (with or without trailing newline);
282 or str to write
283 """
284 with open(fname, 'w', encoding='utf-8') as out:
285 if isinstance(data, list):
286 for line in data:
287 print(line.rstrip('\n'), file=out)
288 else:
289 out.write(data)
290
Simon Glassb2e83c62021-12-18 14:54:31 -0700291def cleanup_empty_blocks(header_path, args):
Chris Packham4d9dbb12019-01-30 20:23:16 +1300292 """Clean up empty conditional blocks
293
294 Arguments:
295 header_path: path to the cleaned file.
Simon Glassb2e83c62021-12-18 14:54:31 -0700296 args: program arguments
Chris Packham4d9dbb12019-01-30 20:23:16 +1300297 """
298 pattern = re.compile(r'^\s*#\s*if.*$\n^\s*#\s*endif.*$\n*', flags=re.M)
299 with open(header_path) as f:
Simon Glass7570d9b2021-03-26 16:17:29 +1300300 try:
301 data = f.read()
302 except UnicodeDecodeError as e:
303 print("Failed on file %s': %s" % (header_path, e))
304 return
Chris Packham4d9dbb12019-01-30 20:23:16 +1300305
306 new_data = pattern.sub('\n', data)
307
308 show_diff(data.splitlines(True), new_data.splitlines(True), header_path,
Simon Glassb2e83c62021-12-18 14:54:31 -0700309 args.color)
Chris Packham4d9dbb12019-01-30 20:23:16 +1300310
Simon Glassb2e83c62021-12-18 14:54:31 -0700311 if args.dry_run:
Chris Packham4d9dbb12019-01-30 20:23:16 +1300312 return
313
Simon Glass2fd85bd2021-12-18 14:54:33 -0700314 write_file(header_path, new_data)
Chris Packham4d9dbb12019-01-30 20:23:16 +1300315
Simon Glassb2e83c62021-12-18 14:54:31 -0700316def cleanup_one_header(header_path, patterns, args):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900317 """Clean regex-matched lines away from a file.
318
319 Arguments:
320 header_path: path to the cleaned file.
321 patterns: list of regex patterns. Any lines matching to these
322 patterns are deleted.
Simon Glassb2e83c62021-12-18 14:54:31 -0700323 args: program arguments
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900324 """
325 with open(header_path) as f:
Simon Glass7570d9b2021-03-26 16:17:29 +1300326 try:
327 lines = f.readlines()
328 except UnicodeDecodeError as e:
329 print("Failed on file %s': %s" % (header_path, e))
330 return
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900331
332 matched = []
333 for i, line in enumerate(lines):
Masahiro Yamadaa3a779f2016-07-25 19:15:27 +0900334 if i - 1 in matched and lines[i - 1][-2:] == '\\\n':
335 matched.append(i)
336 continue
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900337 for pattern in patterns:
Masahiro Yamada8ba1f5d2016-07-25 19:15:24 +0900338 if pattern.search(line):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900339 matched.append(i)
340 break
341
Masahiro Yamada8ba1f5d2016-07-25 19:15:24 +0900342 if not matched:
343 return
344
345 # remove empty #ifdef ... #endif, successive blank lines
346 pattern_if = re.compile(r'#\s*if(def|ndef)?\W') # #if, #ifdef, #ifndef
347 pattern_elif = re.compile(r'#\s*el(if|se)\W') # #elif, #else
348 pattern_endif = re.compile(r'#\s*endif\W') # #endif
349 pattern_blank = re.compile(r'^\s*$') # empty line
350
351 while True:
352 old_matched = copy.copy(matched)
353 extend_matched_lines(lines, matched, [pattern_if],
354 [pattern_endif], True, True)
355 extend_matched_lines(lines, matched, [pattern_elif],
356 [pattern_elif, pattern_endif], True, False)
357 extend_matched_lines(lines, matched, [pattern_if, pattern_elif],
358 [pattern_blank], False, True)
359 extend_matched_lines(lines, matched, [pattern_blank],
360 [pattern_elif, pattern_endif], True, False)
361 extend_matched_lines(lines, matched, [pattern_blank],
362 [pattern_blank], True, False)
363 if matched == old_matched:
364 break
365
Masahiro Yamadaf2f69812016-07-25 19:15:25 +0900366 tolines = copy.copy(lines)
367
368 for i in reversed(matched):
369 tolines.pop(i)
370
Simon Glassb2e83c62021-12-18 14:54:31 -0700371 show_diff(lines, tolines, header_path, args.color)
Masahiro Yamada8ba1f5d2016-07-25 19:15:24 +0900372
Simon Glassb2e83c62021-12-18 14:54:31 -0700373 if args.dry_run:
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900374 return
375
Simon Glass2fd85bd2021-12-18 14:54:33 -0700376 write_file(header_path, tolines)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900377
Simon Glassb2e83c62021-12-18 14:54:31 -0700378def cleanup_headers(configs, args):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900379 """Delete config defines from board headers.
380
381 Arguments:
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900382 configs: A list of CONFIGs to remove.
Simon Glassb2e83c62021-12-18 14:54:31 -0700383 args: program arguments
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900384 """
Simon Glassb2e83c62021-12-18 14:54:31 -0700385 if not confirm(args, 'Clean up headers?'):
Chris Packham85edfc12017-05-02 21:30:46 +1200386 return
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900387
388 patterns = []
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900389 for config in configs:
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900390 patterns.append(re.compile(r'#\s*define\s+%s\W' % config))
391 patterns.append(re.compile(r'#\s*undef\s+%s\W' % config))
392
Joe Hershberger60727f52015-05-19 13:21:21 -0500393 for dir in 'include', 'arch', 'board':
394 for (dirpath, dirnames, filenames) in os.walk(dir):
Masahiro Yamadadc6de502016-07-25 19:15:22 +0900395 if dirpath == os.path.join('include', 'generated'):
396 continue
Joe Hershberger60727f52015-05-19 13:21:21 -0500397 for filename in filenames:
Simon Glassa38cc172020-08-11 11:23:34 -0600398 if not filename.endswith(('~', '.dts', '.dtsi', '.bin',
Trevor Woernerdc514d72021-03-15 12:01:33 -0400399 '.elf','.aml','.dat')):
Chris Packham4d9dbb12019-01-30 20:23:16 +1300400 header_path = os.path.join(dirpath, filename)
Tom Rini02b56702019-11-10 21:19:37 -0500401 # This file contains UTF-16 data and no CONFIG symbols
402 if header_path == 'include/video_font_data.h':
403 continue
Simon Glassb2e83c62021-12-18 14:54:31 -0700404 cleanup_one_header(header_path, patterns, args)
405 cleanup_empty_blocks(header_path, args)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900406
Simon Glassb2e83c62021-12-18 14:54:31 -0700407def cleanup_one_extra_option(defconfig_path, configs, args):
Masahiro Yamada9ab02962016-07-25 19:15:29 +0900408 """Delete config defines in CONFIG_SYS_EXTRA_OPTIONS in one defconfig file.
409
410 Arguments:
411 defconfig_path: path to the cleaned defconfig file.
412 configs: A list of CONFIGs to remove.
Simon Glassb2e83c62021-12-18 14:54:31 -0700413 args: program arguments
Masahiro Yamada9ab02962016-07-25 19:15:29 +0900414 """
415
416 start = 'CONFIG_SYS_EXTRA_OPTIONS="'
417 end = '"\n'
418
419 with open(defconfig_path) as f:
420 lines = f.readlines()
421
422 for i, line in enumerate(lines):
423 if line.startswith(start) and line.endswith(end):
424 break
425 else:
426 # CONFIG_SYS_EXTRA_OPTIONS was not found in this defconfig
427 return
428
429 old_tokens = line[len(start):-len(end)].split(',')
430 new_tokens = []
431
432 for token in old_tokens:
433 pos = token.find('=')
434 if not (token[:pos] if pos >= 0 else token) in configs:
435 new_tokens.append(token)
436
437 if new_tokens == old_tokens:
438 return
439
440 tolines = copy.copy(lines)
441
442 if new_tokens:
443 tolines[i] = start + ','.join(new_tokens) + end
444 else:
445 tolines.pop(i)
446
Simon Glassb2e83c62021-12-18 14:54:31 -0700447 show_diff(lines, tolines, defconfig_path, args.color)
Masahiro Yamada9ab02962016-07-25 19:15:29 +0900448
Simon Glassb2e83c62021-12-18 14:54:31 -0700449 if args.dry_run:
Masahiro Yamada9ab02962016-07-25 19:15:29 +0900450 return
451
Simon Glass2fd85bd2021-12-18 14:54:33 -0700452 write_file(defconfig_path, tolines)
Masahiro Yamada9ab02962016-07-25 19:15:29 +0900453
Simon Glassb2e83c62021-12-18 14:54:31 -0700454def cleanup_extra_options(configs, args):
Masahiro Yamada9ab02962016-07-25 19:15:29 +0900455 """Delete config defines in CONFIG_SYS_EXTRA_OPTIONS in defconfig files.
456
457 Arguments:
458 configs: A list of CONFIGs to remove.
Simon Glassb2e83c62021-12-18 14:54:31 -0700459 args: program arguments
Masahiro Yamada9ab02962016-07-25 19:15:29 +0900460 """
Simon Glassb2e83c62021-12-18 14:54:31 -0700461 if not confirm(args, 'Clean up CONFIG_SYS_EXTRA_OPTIONS?'):
Chris Packham85edfc12017-05-02 21:30:46 +1200462 return
Masahiro Yamada9ab02962016-07-25 19:15:29 +0900463
464 configs = [ config[len('CONFIG_'):] for config in configs ]
465
466 defconfigs = get_all_defconfigs()
467
468 for defconfig in defconfigs:
469 cleanup_one_extra_option(os.path.join('configs', defconfig), configs,
Simon Glassb2e83c62021-12-18 14:54:31 -0700470 args)
Masahiro Yamada9ab02962016-07-25 19:15:29 +0900471
Simon Glassb2e83c62021-12-18 14:54:31 -0700472def cleanup_whitelist(configs, args):
Chris Packhamca438342017-05-02 21:30:47 +1200473 """Delete config whitelist entries
474
475 Arguments:
476 configs: A list of CONFIGs to remove.
Simon Glassb2e83c62021-12-18 14:54:31 -0700477 args: program arguments
Chris Packhamca438342017-05-02 21:30:47 +1200478 """
Simon Glassb2e83c62021-12-18 14:54:31 -0700479 if not confirm(args, 'Clean up whitelist entries?'):
Chris Packhamca438342017-05-02 21:30:47 +1200480 return
481
482 with open(os.path.join('scripts', 'config_whitelist.txt')) as f:
483 lines = f.readlines()
484
485 lines = [x for x in lines if x.strip() not in configs]
486
Simon Glass2fd85bd2021-12-18 14:54:33 -0700487 write_file(os.path.join('scripts', 'config_whitelist.txt'), lines)
Chris Packhamca438342017-05-02 21:30:47 +1200488
Chris Packhamf90df592017-05-02 21:30:48 +1200489def find_matching(patterns, line):
490 for pat in patterns:
491 if pat.search(line):
492 return True
493 return False
494
Simon Glassb2e83c62021-12-18 14:54:31 -0700495def cleanup_readme(configs, args):
Chris Packhamf90df592017-05-02 21:30:48 +1200496 """Delete config description in README
497
498 Arguments:
499 configs: A list of CONFIGs to remove.
Simon Glassb2e83c62021-12-18 14:54:31 -0700500 args: program arguments
Chris Packhamf90df592017-05-02 21:30:48 +1200501 """
Simon Glassb2e83c62021-12-18 14:54:31 -0700502 if not confirm(args, 'Clean up README?'):
Chris Packhamf90df592017-05-02 21:30:48 +1200503 return
504
505 patterns = []
506 for config in configs:
507 patterns.append(re.compile(r'^\s+%s' % config))
508
509 with open('README') as f:
510 lines = f.readlines()
511
512 found = False
513 newlines = []
514 for line in lines:
515 if not found:
516 found = find_matching(patterns, line)
517 if found:
518 continue
519
520 if found and re.search(r'^\s+CONFIG', line):
521 found = False
522
523 if not found:
524 newlines.append(line)
525
Simon Glass2fd85bd2021-12-18 14:54:33 -0700526 write_file('README', newlines)
Chris Packhamf90df592017-05-02 21:30:48 +1200527
Markus Klotzbuecherb237d352019-05-15 15:15:52 +0200528def try_expand(line):
529 """If value looks like an expression, try expanding it
530 Otherwise just return the existing value
531 """
532 if line.find('=') == -1:
533 return line
534
535 try:
Markus Klotzbuecherb3192f42020-02-12 20:46:44 +0100536 aeval = asteval.Interpreter( usersyms=SIZES, minimal=True )
Markus Klotzbuecherb237d352019-05-15 15:15:52 +0200537 cfg, val = re.split("=", line)
538 val= val.strip('\"')
Simon Glassdaa694d2021-12-18 14:54:30 -0700539 if re.search(r'[*+-/]|<<|SZ_+|\(([^\)]+)\)', val):
Markus Klotzbuecherb3192f42020-02-12 20:46:44 +0100540 newval = hex(aeval(val))
Simon Glassdaa694d2021-12-18 14:54:30 -0700541 print('\tExpanded expression %s to %s' % (val, newval))
Markus Klotzbuecherb237d352019-05-15 15:15:52 +0200542 return cfg+'='+newval
543 except:
Simon Glassdaa694d2021-12-18 14:54:30 -0700544 print('\tFailed to expand expression in %s' % line)
Markus Klotzbuecherb237d352019-05-15 15:15:52 +0200545
546 return line
547
Chris Packhamca438342017-05-02 21:30:47 +1200548
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900549### classes ###
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +0900550class Progress:
551
552 """Progress Indicator"""
553
554 def __init__(self, total):
555 """Create a new progress indicator.
556
557 Arguments:
558 total: A number of defconfig files to process.
559 """
560 self.current = 0
561 self.total = total
562
563 def inc(self):
564 """Increment the number of processed defconfig files."""
565
566 self.current += 1
567
568 def show(self):
569 """Display the progress."""
Simon Glass793dca32019-10-31 07:42:57 -0600570 print(' %d defconfigs out of %d\r' % (self.current, self.total), end=' ')
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +0900571 sys.stdout.flush()
572
Simon Glasscb008832017-06-15 21:39:33 -0600573
574class KconfigScanner:
575 """Kconfig scanner."""
576
577 def __init__(self):
578 """Scan all the Kconfig files and create a Config object."""
579 # Define environment variables referenced from Kconfig
580 os.environ['srctree'] = os.getcwd()
581 os.environ['UBOOTVERSION'] = 'dummy'
582 os.environ['KCONFIG_OBJDIR'] = ''
Tom Rini65e05dd2019-09-20 17:42:09 -0400583 self.conf = kconfiglib.Kconfig()
Simon Glasscb008832017-06-15 21:39:33 -0600584
585
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900586class KconfigParser:
587
588 """A parser of .config and include/autoconf.mk."""
589
590 re_arch = re.compile(r'CONFIG_SYS_ARCH="(.*)"')
591 re_cpu = re.compile(r'CONFIG_SYS_CPU="(.*)"')
592
Simon Glassb2e83c62021-12-18 14:54:31 -0700593 def __init__(self, configs, args, build_dir):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900594 """Create a new parser.
595
596 Arguments:
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900597 configs: A list of CONFIGs to move.
Simon Glassb2e83c62021-12-18 14:54:31 -0700598 args: program arguments
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900599 build_dir: Build directory.
600 """
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900601 self.configs = configs
Simon Glassb2e83c62021-12-18 14:54:31 -0700602 self.args = args
Masahiro Yamada1f169922016-05-19 15:52:00 +0900603 self.dotconfig = os.path.join(build_dir, '.config')
604 self.autoconf = os.path.join(build_dir, 'include', 'autoconf.mk')
Masahiro Yamada07913d12016-08-22 22:18:22 +0900605 self.spl_autoconf = os.path.join(build_dir, 'spl', 'include',
606 'autoconf.mk')
Simon Glassf3b8e642017-06-01 19:39:01 -0600607 self.config_autoconf = os.path.join(build_dir, AUTO_CONF_PATH)
Masahiro Yamada5da4f852016-05-19 15:52:06 +0900608 self.defconfig = os.path.join(build_dir, 'defconfig')
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900609
Simon Glass6821a742017-07-10 14:47:47 -0600610 def get_arch(self):
611 """Parse .config file and return the architecture.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900612
613 Returns:
Simon Glass6821a742017-07-10 14:47:47 -0600614 Architecture name (e.g. 'arm').
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900615 """
616 arch = ''
617 cpu = ''
Masahiro Yamada1f169922016-05-19 15:52:00 +0900618 for line in open(self.dotconfig):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900619 m = self.re_arch.match(line)
620 if m:
621 arch = m.group(1)
622 continue
623 m = self.re_cpu.match(line)
624 if m:
625 cpu = m.group(1)
626
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +0900627 if not arch:
628 return None
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900629
630 # fix-up for aarch64
631 if arch == 'arm' and cpu == 'armv8':
632 arch = 'aarch64'
633
Simon Glass6821a742017-07-10 14:47:47 -0600634 return arch
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900635
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900636 def parse_one_config(self, config, dotconfig_lines, autoconf_lines):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900637 """Parse .config, defconfig, include/autoconf.mk for one config.
638
639 This function looks for the config options in the lines from
640 defconfig, .config, and include/autoconf.mk in order to decide
641 which action should be taken for this defconfig.
642
643 Arguments:
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900644 config: CONFIG name to parse.
Masahiro Yamadacc008292016-05-19 15:51:56 +0900645 dotconfig_lines: lines from the .config file.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900646 autoconf_lines: lines from the include/autoconf.mk file.
647
648 Returns:
649 A tupple of the action for this defconfig and the line
650 matched for the config.
651 """
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900652 not_set = '# %s is not set' % config
653
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900654 for line in autoconf_lines:
655 line = line.rstrip()
656 if line.startswith(config + '='):
Masahiro Yamadacc008292016-05-19 15:51:56 +0900657 new_val = line
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900658 break
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900659 else:
Masahiro Yamadacc008292016-05-19 15:51:56 +0900660 new_val = not_set
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900661
Markus Klotzbuecherb237d352019-05-15 15:15:52 +0200662 new_val = try_expand(new_val)
663
Masahiro Yamada916224c2016-08-22 22:18:21 +0900664 for line in dotconfig_lines:
665 line = line.rstrip()
666 if line.startswith(config + '=') or line == not_set:
667 old_val = line
668 break
669 else:
670 if new_val == not_set:
671 return (ACTION_NO_ENTRY, config)
672 else:
673 return (ACTION_NO_ENTRY_WARN, config)
674
Masahiro Yamadacc008292016-05-19 15:51:56 +0900675 # If this CONFIG is neither bool nor trisate
676 if old_val[-2:] != '=y' and old_val[-2:] != '=m' and old_val != not_set:
677 # tools/scripts/define2mk.sed changes '1' to 'y'.
678 # This is a problem if the CONFIG is int type.
679 # Check the type in Kconfig and handle it correctly.
680 if new_val[-2:] == '=y':
681 new_val = new_val[:-1] + '1'
682
Masahiro Yamada50301592016-06-15 14:33:50 +0900683 return (ACTION_NO_CHANGE if old_val == new_val else ACTION_MOVE,
684 new_val)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900685
Masahiro Yamada1d085562016-05-19 15:52:02 +0900686 def update_dotconfig(self):
Masahiro Yamada6ff36d22016-05-19 15:51:50 +0900687 """Parse files for the config options and update the .config.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900688
Masahiro Yamadacc008292016-05-19 15:51:56 +0900689 This function parses the generated .config and include/autoconf.mk
690 searching the target options.
Masahiro Yamada6ff36d22016-05-19 15:51:50 +0900691 Move the config option(s) to the .config as needed.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900692
693 Arguments:
694 defconfig: defconfig name.
Masahiro Yamada522e8dc2016-05-19 15:52:01 +0900695
696 Returns:
Masahiro Yamada7fb0bac2016-05-19 15:52:04 +0900697 Return a tuple of (updated flag, log string).
698 The "updated flag" is True if the .config was updated, False
699 otherwise. The "log string" shows what happend to the .config.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900700 """
701
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900702 results = []
Masahiro Yamada7fb0bac2016-05-19 15:52:04 +0900703 updated = False
Masahiro Yamada916224c2016-08-22 22:18:21 +0900704 suspicious = False
Masahiro Yamada07913d12016-08-22 22:18:22 +0900705 rm_files = [self.config_autoconf, self.autoconf]
706
Simon Glassb2e83c62021-12-18 14:54:31 -0700707 if self.args.spl:
Masahiro Yamada07913d12016-08-22 22:18:22 +0900708 if os.path.exists(self.spl_autoconf):
709 autoconf_path = self.spl_autoconf
710 rm_files.append(self.spl_autoconf)
711 else:
712 for f in rm_files:
713 os.remove(f)
714 return (updated, suspicious,
Simon Glassb2e83c62021-12-18 14:54:31 -0700715 color_text(self.args.color, COLOR_BROWN,
Masahiro Yamada07913d12016-08-22 22:18:22 +0900716 "SPL is not enabled. Skipped.") + '\n')
717 else:
718 autoconf_path = self.autoconf
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900719
Masahiro Yamada1f169922016-05-19 15:52:00 +0900720 with open(self.dotconfig) as f:
Masahiro Yamadacc008292016-05-19 15:51:56 +0900721 dotconfig_lines = f.readlines()
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900722
Masahiro Yamada07913d12016-08-22 22:18:22 +0900723 with open(autoconf_path) as f:
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900724 autoconf_lines = f.readlines()
725
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900726 for config in self.configs:
727 result = self.parse_one_config(config, dotconfig_lines,
Joe Hershberger96464ba2015-05-19 13:21:17 -0500728 autoconf_lines)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900729 results.append(result)
730
731 log = ''
732
733 for (action, value) in results:
734 if action == ACTION_MOVE:
735 actlog = "Move '%s'" % value
736 log_color = COLOR_LIGHT_GREEN
Masahiro Yamadacc008292016-05-19 15:51:56 +0900737 elif action == ACTION_NO_ENTRY:
Simon Glassdaa694d2021-12-18 14:54:30 -0700738 actlog = '%s is not defined in Kconfig. Do nothing.' % value
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900739 log_color = COLOR_LIGHT_BLUE
Masahiro Yamada916224c2016-08-22 22:18:21 +0900740 elif action == ACTION_NO_ENTRY_WARN:
Simon Glassdaa694d2021-12-18 14:54:30 -0700741 actlog = '%s is not defined in Kconfig (suspicious). Do nothing.' % value
Masahiro Yamada916224c2016-08-22 22:18:21 +0900742 log_color = COLOR_YELLOW
743 suspicious = True
Masahiro Yamadacc008292016-05-19 15:51:56 +0900744 elif action == ACTION_NO_CHANGE:
745 actlog = "'%s' is the same as the define in Kconfig. Do nothing." \
746 % value
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900747 log_color = COLOR_LIGHT_PURPLE
Masahiro Yamada07913d12016-08-22 22:18:22 +0900748 elif action == ACTION_SPL_NOT_EXIST:
Simon Glassdaa694d2021-12-18 14:54:30 -0700749 actlog = 'SPL is not enabled for this defconfig. Skip.'
Masahiro Yamada07913d12016-08-22 22:18:22 +0900750 log_color = COLOR_PURPLE
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900751 else:
Simon Glassdaa694d2021-12-18 14:54:30 -0700752 sys.exit('Internal Error. This should not happen.')
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900753
Simon Glassb2e83c62021-12-18 14:54:31 -0700754 log += color_text(self.args.color, log_color, actlog) + '\n'
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900755
Masahiro Yamada1f169922016-05-19 15:52:00 +0900756 with open(self.dotconfig, 'a') as f:
Masahiro Yamadae423d172016-05-19 15:51:49 +0900757 for (action, value) in results:
758 if action == ACTION_MOVE:
759 f.write(value + '\n')
Masahiro Yamada7fb0bac2016-05-19 15:52:04 +0900760 updated = True
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900761
Masahiro Yamada5da4f852016-05-19 15:52:06 +0900762 self.results = results
Masahiro Yamada07913d12016-08-22 22:18:22 +0900763 for f in rm_files:
764 os.remove(f)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900765
Masahiro Yamada916224c2016-08-22 22:18:21 +0900766 return (updated, suspicious, log)
Masahiro Yamada522e8dc2016-05-19 15:52:01 +0900767
Masahiro Yamada5da4f852016-05-19 15:52:06 +0900768 def check_defconfig(self):
769 """Check the defconfig after savedefconfig
770
771 Returns:
772 Return additional log if moved CONFIGs were removed again by
773 'make savedefconfig'.
774 """
775
776 log = ''
777
778 with open(self.defconfig) as f:
779 defconfig_lines = f.readlines()
780
781 for (action, value) in self.results:
782 if action != ACTION_MOVE:
783 continue
784 if not value + '\n' in defconfig_lines:
Simon Glassb2e83c62021-12-18 14:54:31 -0700785 log += color_text(self.args.color, COLOR_YELLOW,
Masahiro Yamada5da4f852016-05-19 15:52:06 +0900786 "'%s' was removed by savedefconfig.\n" %
787 value)
788
789 return log
790
Simon Glassd73fcb12017-06-01 19:39:02 -0600791
792class DatabaseThread(threading.Thread):
793 """This thread processes results from Slot threads.
794
795 It collects the data in the master config directary. There is only one
796 result thread, and this helps to serialise the build output.
797 """
798 def __init__(self, config_db, db_queue):
799 """Set up a new result thread
800
801 Args:
802 builder: Builder which will be sent each result
803 """
804 threading.Thread.__init__(self)
805 self.config_db = config_db
806 self.db_queue= db_queue
807
808 def run(self):
809 """Called to start up the result thread.
810
811 We collect the next result job and pass it on to the build.
812 """
813 while True:
814 defconfig, configs = self.db_queue.get()
815 self.config_db[defconfig] = configs
816 self.db_queue.task_done()
817
818
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900819class Slot:
820
821 """A slot to store a subprocess.
822
823 Each instance of this class handles one subprocess.
824 This class is useful to control multiple threads
825 for faster processing.
826 """
827
Simon Glassb2e83c62021-12-18 14:54:31 -0700828 def __init__(self, toolchains, configs, args, progress, devnull,
Simon Glass6821a742017-07-10 14:47:47 -0600829 make_cmd, reference_src_dir, db_queue):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900830 """Create a new process slot.
831
832 Arguments:
Simon Glass6821a742017-07-10 14:47:47 -0600833 toolchains: Toolchains object containing toolchains.
Masahiro Yamadab134bc12016-05-19 15:51:57 +0900834 configs: A list of CONFIGs to move.
Simon Glassb2e83c62021-12-18 14:54:31 -0700835 args: Program arguments
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +0900836 progress: A progress indicator.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900837 devnull: A file object of '/dev/null'.
838 make_cmd: command name of GNU Make.
Joe Hershberger6b96c1a2016-06-10 14:53:32 -0500839 reference_src_dir: Determine the true starting config state from this
840 source tree.
Simon Glassd73fcb12017-06-01 19:39:02 -0600841 db_queue: output queue to write config info for the database
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900842 """
Simon Glass6821a742017-07-10 14:47:47 -0600843 self.toolchains = toolchains
Simon Glassb2e83c62021-12-18 14:54:31 -0700844 self.args = args
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +0900845 self.progress = progress
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900846 self.build_dir = tempfile.mkdtemp()
847 self.devnull = devnull
848 self.make_cmd = (make_cmd, 'O=' + self.build_dir)
Joe Hershberger6b96c1a2016-06-10 14:53:32 -0500849 self.reference_src_dir = reference_src_dir
Simon Glassd73fcb12017-06-01 19:39:02 -0600850 self.db_queue = db_queue
Simon Glassb2e83c62021-12-18 14:54:31 -0700851 self.parser = KconfigParser(configs, args, self.build_dir)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900852 self.state = STATE_IDLE
Masahiro Yamada09c6c062016-08-22 22:18:20 +0900853 self.failed_boards = set()
854 self.suspicious_boards = set()
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900855
856 def __del__(self):
857 """Delete the working directory
858
859 This function makes sure the temporary directory is cleaned away
860 even if Python suddenly dies due to error. It should be done in here
Joe Hershbergerf2dae752016-06-10 14:53:29 -0500861 because it is guaranteed the destructor is always invoked when the
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900862 instance of the class gets unreferenced.
863
864 If the subprocess is still running, wait until it finishes.
865 """
866 if self.state != STATE_IDLE:
867 while self.ps.poll() == None:
868 pass
869 shutil.rmtree(self.build_dir)
870
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +0900871 def add(self, defconfig):
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900872 """Assign a new subprocess for defconfig and add it to the slot.
873
874 If the slot is vacant, create a new subprocess for processing the
875 given defconfig and add it to the slot. Just returns False if
876 the slot is occupied (i.e. the current subprocess is still running).
877
878 Arguments:
879 defconfig: defconfig name.
880
881 Returns:
882 Return True on success or False on failure
883 """
884 if self.state != STATE_IDLE:
885 return False
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900886
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900887 self.defconfig = defconfig
Masahiro Yamada1d085562016-05-19 15:52:02 +0900888 self.log = ''
Masahiro Yamadaf432c332016-06-15 14:33:52 +0900889 self.current_src_dir = self.reference_src_dir
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900890 self.do_defconfig()
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900891 return True
892
893 def poll(self):
894 """Check the status of the subprocess and handle it as needed.
895
896 Returns True if the slot is vacant (i.e. in idle state).
897 If the configuration is successfully finished, assign a new
898 subprocess to build include/autoconf.mk.
899 If include/autoconf.mk is generated, invoke the parser to
Masahiro Yamada7fb0bac2016-05-19 15:52:04 +0900900 parse the .config and the include/autoconf.mk, moving
901 config options to the .config as needed.
902 If the .config was updated, run "make savedefconfig" to sync
903 it, update the original defconfig, and then set the slot back
904 to the idle state.
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900905
906 Returns:
907 Return True if the subprocess is terminated, False otherwise
908 """
909 if self.state == STATE_IDLE:
910 return True
911
912 if self.ps.poll() == None:
913 return False
914
915 if self.ps.poll() != 0:
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900916 self.handle_error()
917 elif self.state == STATE_DEFCONFIG:
Masahiro Yamadaf432c332016-06-15 14:33:52 +0900918 if self.reference_src_dir and not self.current_src_dir:
Joe Hershberger6b96c1a2016-06-10 14:53:32 -0500919 self.do_savedefconfig()
920 else:
921 self.do_autoconf()
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900922 elif self.state == STATE_AUTOCONF:
Masahiro Yamadaf432c332016-06-15 14:33:52 +0900923 if self.current_src_dir:
924 self.current_src_dir = None
Joe Hershberger6b96c1a2016-06-10 14:53:32 -0500925 self.do_defconfig()
Simon Glassb2e83c62021-12-18 14:54:31 -0700926 elif self.args.build_db:
Simon Glassd73fcb12017-06-01 19:39:02 -0600927 self.do_build_db()
Joe Hershberger6b96c1a2016-06-10 14:53:32 -0500928 else:
929 self.do_savedefconfig()
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900930 elif self.state == STATE_SAVEDEFCONFIG:
931 self.update_defconfig()
932 else:
Simon Glassdaa694d2021-12-18 14:54:30 -0700933 sys.exit('Internal Error. This should not happen.')
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900934
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900935 return True if self.state == STATE_IDLE else False
Joe Hershberger96464ba2015-05-19 13:21:17 -0500936
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900937 def handle_error(self):
938 """Handle error cases."""
Masahiro Yamada8513dc02016-05-19 15:52:08 +0900939
Simon Glassb2e83c62021-12-18 14:54:31 -0700940 self.log += color_text(self.args.color, COLOR_LIGHT_RED,
Simon Glassdaa694d2021-12-18 14:54:30 -0700941 'Failed to process.\n')
Simon Glassb2e83c62021-12-18 14:54:31 -0700942 if self.args.verbose:
943 self.log += color_text(self.args.color, COLOR_LIGHT_CYAN,
Markus Klotzbuecher4f5c5e92020-02-12 20:46:45 +0100944 self.ps.stderr.read().decode())
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900945 self.finish(False)
Joe Hershberger96464ba2015-05-19 13:21:17 -0500946
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900947 def do_defconfig(self):
948 """Run 'make <board>_defconfig' to create the .config file."""
Masahiro Yamadac8e1b102016-05-19 15:52:07 +0900949
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900950 cmd = list(self.make_cmd)
951 cmd.append(self.defconfig)
952 self.ps = subprocess.Popen(cmd, stdout=self.devnull,
Masahiro Yamadaf432c332016-06-15 14:33:52 +0900953 stderr=subprocess.PIPE,
954 cwd=self.current_src_dir)
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900955 self.state = STATE_DEFCONFIG
Masahiro Yamadac8e1b102016-05-19 15:52:07 +0900956
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900957 def do_autoconf(self):
Simon Glassf3b8e642017-06-01 19:39:01 -0600958 """Run 'make AUTO_CONF_PATH'."""
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900959
Simon Glass6821a742017-07-10 14:47:47 -0600960 arch = self.parser.get_arch()
961 try:
962 toolchain = self.toolchains.Select(arch)
963 except ValueError:
Simon Glassb2e83c62021-12-18 14:54:31 -0700964 self.log += color_text(self.args.color, COLOR_YELLOW,
Chris Packhamce3ba452017-08-27 20:00:51 +1200965 "Tool chain for '%s' is missing. Do nothing.\n" % arch)
Masahiro Yamada4efef992016-05-19 15:52:03 +0900966 self.finish(False)
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900967 return
Simon Glass793dca32019-10-31 07:42:57 -0600968 env = toolchain.MakeEnvironment(False)
Masahiro Yamada90ed6cb2016-05-19 15:51:53 +0900969
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900970 cmd = list(self.make_cmd)
Joe Hershberger7740f652015-05-19 13:21:18 -0500971 cmd.append('KCONFIG_IGNORE_DUPLICATES=1')
Simon Glassf3b8e642017-06-01 19:39:01 -0600972 cmd.append(AUTO_CONF_PATH)
Simon Glass6821a742017-07-10 14:47:47 -0600973 self.ps = subprocess.Popen(cmd, stdout=self.devnull, env=env,
Masahiro Yamadaf432c332016-06-15 14:33:52 +0900974 stderr=subprocess.PIPE,
975 cwd=self.current_src_dir)
Masahiro Yamada5a27c732015-05-20 11:36:07 +0900976 self.state = STATE_AUTOCONF
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900977
Simon Glassd73fcb12017-06-01 19:39:02 -0600978 def do_build_db(self):
979 """Add the board to the database"""
980 configs = {}
981 with open(os.path.join(self.build_dir, AUTO_CONF_PATH)) as fd:
982 for line in fd.readlines():
983 if line.startswith('CONFIG'):
984 config, value = line.split('=', 1)
985 configs[config] = value.rstrip()
986 self.db_queue.put([self.defconfig, configs])
987 self.finish(True)
988
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900989 def do_savedefconfig(self):
990 """Update the .config and run 'make savedefconfig'."""
991
Masahiro Yamada916224c2016-08-22 22:18:21 +0900992 (updated, suspicious, log) = self.parser.update_dotconfig()
993 if suspicious:
994 self.suspicious_boards.add(self.defconfig)
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900995 self.log += log
996
Simon Glassb2e83c62021-12-18 14:54:31 -0700997 if not self.args.force_sync and not updated:
Masahiro Yamadae307fa92016-06-08 11:47:37 +0900998 self.finish(True)
999 return
1000 if updated:
Simon Glassb2e83c62021-12-18 14:54:31 -07001001 self.log += color_text(self.args.color, COLOR_LIGHT_GREEN,
Simon Glassdaa694d2021-12-18 14:54:30 -07001002 'Syncing by savedefconfig...\n')
Masahiro Yamadae307fa92016-06-08 11:47:37 +09001003 else:
Simon Glassdaa694d2021-12-18 14:54:30 -07001004 self.log += 'Syncing by savedefconfig (forced by option)...\n'
Masahiro Yamadae307fa92016-06-08 11:47:37 +09001005
1006 cmd = list(self.make_cmd)
1007 cmd.append('savedefconfig')
1008 self.ps = subprocess.Popen(cmd, stdout=self.devnull,
1009 stderr=subprocess.PIPE)
1010 self.state = STATE_SAVEDEFCONFIG
1011
1012 def update_defconfig(self):
1013 """Update the input defconfig and go back to the idle state."""
1014
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001015 log = self.parser.check_defconfig()
1016 if log:
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001017 self.suspicious_boards.add(self.defconfig)
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001018 self.log += log
Masahiro Yamadae307fa92016-06-08 11:47:37 +09001019 orig_defconfig = os.path.join('configs', self.defconfig)
1020 new_defconfig = os.path.join(self.build_dir, 'defconfig')
1021 updated = not filecmp.cmp(orig_defconfig, new_defconfig)
1022
1023 if updated:
Simon Glassb2e83c62021-12-18 14:54:31 -07001024 self.log += color_text(self.args.color, COLOR_LIGHT_BLUE,
Simon Glassdaa694d2021-12-18 14:54:30 -07001025 'defconfig was updated.\n')
Masahiro Yamadae307fa92016-06-08 11:47:37 +09001026
Simon Glassb2e83c62021-12-18 14:54:31 -07001027 if not self.args.dry_run and updated:
Masahiro Yamadae307fa92016-06-08 11:47:37 +09001028 shutil.move(new_defconfig, orig_defconfig)
1029 self.finish(True)
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001030
Masahiro Yamada4efef992016-05-19 15:52:03 +09001031 def finish(self, success):
1032 """Display log along with progress and go to the idle state.
Masahiro Yamada1d085562016-05-19 15:52:02 +09001033
1034 Arguments:
Masahiro Yamada4efef992016-05-19 15:52:03 +09001035 success: Should be True when the defconfig was processed
1036 successfully, or False when it fails.
Masahiro Yamada1d085562016-05-19 15:52:02 +09001037 """
1038 # output at least 30 characters to hide the "* defconfigs out of *".
1039 log = self.defconfig.ljust(30) + '\n'
1040
1041 log += '\n'.join([ ' ' + s for s in self.log.split('\n') ])
1042 # Some threads are running in parallel.
1043 # Print log atomically to not mix up logs from different threads.
Simon Glass793dca32019-10-31 07:42:57 -06001044 print(log, file=(sys.stdout if success else sys.stderr))
Masahiro Yamada4efef992016-05-19 15:52:03 +09001045
1046 if not success:
Simon Glassb2e83c62021-12-18 14:54:31 -07001047 if self.args.exit_on_error:
Simon Glassdaa694d2021-12-18 14:54:30 -07001048 sys.exit('Exit on error.')
Masahiro Yamada4efef992016-05-19 15:52:03 +09001049 # If --exit-on-error flag is not set, skip this board and continue.
1050 # Record the failed board.
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001051 self.failed_boards.add(self.defconfig)
Masahiro Yamada4efef992016-05-19 15:52:03 +09001052
Masahiro Yamada1d085562016-05-19 15:52:02 +09001053 self.progress.inc()
1054 self.progress.show()
Masahiro Yamada4efef992016-05-19 15:52:03 +09001055 self.state = STATE_IDLE
Masahiro Yamada1d085562016-05-19 15:52:02 +09001056
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001057 def get_failed_boards(self):
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001058 """Returns a set of failed boards (defconfigs) in this slot.
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001059 """
1060 return self.failed_boards
1061
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001062 def get_suspicious_boards(self):
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001063 """Returns a set of boards (defconfigs) with possible misconversion.
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001064 """
Masahiro Yamada916224c2016-08-22 22:18:21 +09001065 return self.suspicious_boards - self.failed_boards
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001066
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001067class Slots:
1068
1069 """Controller of the array of subprocess slots."""
1070
Simon Glassb2e83c62021-12-18 14:54:31 -07001071 def __init__(self, toolchains, configs, args, progress,
Simon Glass6821a742017-07-10 14:47:47 -06001072 reference_src_dir, db_queue):
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001073 """Create a new slots controller.
1074
1075 Arguments:
Simon Glass6821a742017-07-10 14:47:47 -06001076 toolchains: Toolchains object containing toolchains.
Masahiro Yamadab134bc12016-05-19 15:51:57 +09001077 configs: A list of CONFIGs to move.
Simon Glassb2e83c62021-12-18 14:54:31 -07001078 args: Program arguments
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +09001079 progress: A progress indicator.
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001080 reference_src_dir: Determine the true starting config state from this
1081 source tree.
Simon Glassd73fcb12017-06-01 19:39:02 -06001082 db_queue: output queue to write config info for the database
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001083 """
Simon Glassb2e83c62021-12-18 14:54:31 -07001084 self.args = args
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001085 self.slots = []
Simon Glass478920d2021-12-18 14:54:32 -07001086 devnull = subprocess.DEVNULL
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001087 make_cmd = get_make_cmd()
Simon Glassb2e83c62021-12-18 14:54:31 -07001088 for i in range(args.jobs):
1089 self.slots.append(Slot(toolchains, configs, args, progress,
Simon Glass6821a742017-07-10 14:47:47 -06001090 devnull, make_cmd, reference_src_dir,
1091 db_queue))
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001092
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +09001093 def add(self, defconfig):
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001094 """Add a new subprocess if a vacant slot is found.
1095
1096 Arguments:
1097 defconfig: defconfig name to be put into.
1098
1099 Returns:
1100 Return True on success or False on failure
1101 """
1102 for slot in self.slots:
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +09001103 if slot.add(defconfig):
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001104 return True
1105 return False
1106
1107 def available(self):
1108 """Check if there is a vacant slot.
1109
1110 Returns:
1111 Return True if at lease one vacant slot is found, False otherwise.
1112 """
1113 for slot in self.slots:
1114 if slot.poll():
1115 return True
1116 return False
1117
1118 def empty(self):
1119 """Check if all slots are vacant.
1120
1121 Returns:
1122 Return True if all the slots are vacant, False otherwise.
1123 """
1124 ret = True
1125 for slot in self.slots:
1126 if not slot.poll():
1127 ret = False
1128 return ret
1129
1130 def show_failed_boards(self):
1131 """Display all of the failed boards (defconfigs)."""
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001132 boards = set()
Masahiro Yamada96dccd92016-06-15 14:33:53 +09001133 output_file = 'moveconfig.failed'
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001134
1135 for slot in self.slots:
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001136 boards |= slot.get_failed_boards()
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001137
Masahiro Yamada96dccd92016-06-15 14:33:53 +09001138 if boards:
1139 boards = '\n'.join(boards) + '\n'
Simon Glassdaa694d2021-12-18 14:54:30 -07001140 msg = 'The following boards were not processed due to error:\n'
Masahiro Yamada96dccd92016-06-15 14:33:53 +09001141 msg += boards
Simon Glassdaa694d2021-12-18 14:54:30 -07001142 msg += '(the list has been saved in %s)\n' % output_file
Simon Glassb2e83c62021-12-18 14:54:31 -07001143 print(color_text(self.args.color, COLOR_LIGHT_RED,
Simon Glass793dca32019-10-31 07:42:57 -06001144 msg), file=sys.stderr)
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001145
Simon Glass2fd85bd2021-12-18 14:54:33 -07001146 write_file(output_file, boards)
Joe Hershberger2559cd82015-05-19 13:21:22 -05001147
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001148 def show_suspicious_boards(self):
1149 """Display all boards (defconfigs) with possible misconversion."""
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001150 boards = set()
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001151 output_file = 'moveconfig.suspicious'
1152
1153 for slot in self.slots:
Masahiro Yamada09c6c062016-08-22 22:18:20 +09001154 boards |= slot.get_suspicious_boards()
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001155
1156 if boards:
1157 boards = '\n'.join(boards) + '\n'
Simon Glassdaa694d2021-12-18 14:54:30 -07001158 msg = 'The following boards might have been converted incorrectly.\n'
1159 msg += 'It is highly recommended to check them manually:\n'
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001160 msg += boards
Simon Glassdaa694d2021-12-18 14:54:30 -07001161 msg += '(the list has been saved in %s)\n' % output_file
Simon Glassb2e83c62021-12-18 14:54:31 -07001162 print(color_text(self.args.color, COLOR_YELLOW,
Simon Glass793dca32019-10-31 07:42:57 -06001163 msg), file=sys.stderr)
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001164
Simon Glass2fd85bd2021-12-18 14:54:33 -07001165 write_file(output_file, boards)
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001166
Masahiro Yamada5cc42a52016-06-15 14:33:51 +09001167class ReferenceSource:
1168
1169 """Reference source against which original configs should be parsed."""
1170
1171 def __init__(self, commit):
1172 """Create a reference source directory based on a specified commit.
1173
1174 Arguments:
1175 commit: commit to git-clone
1176 """
1177 self.src_dir = tempfile.mkdtemp()
Simon Glassdaa694d2021-12-18 14:54:30 -07001178 print('Cloning git repo to a separate work directory...')
Masahiro Yamada5cc42a52016-06-15 14:33:51 +09001179 subprocess.check_output(['git', 'clone', os.getcwd(), '.'],
1180 cwd=self.src_dir)
Simon Glass793dca32019-10-31 07:42:57 -06001181 print("Checkout '%s' to build the original autoconf.mk." % \
1182 subprocess.check_output(['git', 'rev-parse', '--short', commit]).strip())
Masahiro Yamada5cc42a52016-06-15 14:33:51 +09001183 subprocess.check_output(['git', 'checkout', commit],
1184 stderr=subprocess.STDOUT, cwd=self.src_dir)
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001185
1186 def __del__(self):
Masahiro Yamada5cc42a52016-06-15 14:33:51 +09001187 """Delete the reference source directory
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001188
1189 This function makes sure the temporary directory is cleaned away
1190 even if Python suddenly dies due to error. It should be done in here
1191 because it is guaranteed the destructor is always invoked when the
1192 instance of the class gets unreferenced.
1193 """
Masahiro Yamada5cc42a52016-06-15 14:33:51 +09001194 shutil.rmtree(self.src_dir)
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001195
Masahiro Yamada5cc42a52016-06-15 14:33:51 +09001196 def get_dir(self):
1197 """Return the absolute path to the reference source directory."""
1198
1199 return self.src_dir
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001200
Simon Glassb2e83c62021-12-18 14:54:31 -07001201def move_config(toolchains, configs, args, db_queue):
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001202 """Move config options to defconfig files.
1203
1204 Arguments:
Masahiro Yamadab134bc12016-05-19 15:51:57 +09001205 configs: A list of CONFIGs to move.
Simon Glassb2e83c62021-12-18 14:54:31 -07001206 args: Program arguments
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001207 """
Masahiro Yamadab134bc12016-05-19 15:51:57 +09001208 if len(configs) == 0:
Simon Glassb2e83c62021-12-18 14:54:31 -07001209 if args.force_sync:
Simon Glass793dca32019-10-31 07:42:57 -06001210 print('No CONFIG is specified. You are probably syncing defconfigs.', end=' ')
Simon Glassb2e83c62021-12-18 14:54:31 -07001211 elif args.build_db:
Simon Glass793dca32019-10-31 07:42:57 -06001212 print('Building %s database' % CONFIG_DATABASE)
Masahiro Yamada6a9f79f2016-05-19 15:52:09 +09001213 else:
Simon Glass793dca32019-10-31 07:42:57 -06001214 print('Neither CONFIG nor --force-sync is specified. Nothing will happen.', end=' ')
Masahiro Yamada6a9f79f2016-05-19 15:52:09 +09001215 else:
Simon Glass793dca32019-10-31 07:42:57 -06001216 print('Move ' + ', '.join(configs), end=' ')
Simon Glassb2e83c62021-12-18 14:54:31 -07001217 print('(jobs: %d)\n' % args.jobs)
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001218
Simon Glassb2e83c62021-12-18 14:54:31 -07001219 if args.git_ref:
1220 reference_src = ReferenceSource(args.git_ref)
Masahiro Yamada5cc42a52016-06-15 14:33:51 +09001221 reference_src_dir = reference_src.get_dir()
1222 else:
Masahiro Yamadaf432c332016-06-15 14:33:52 +09001223 reference_src_dir = None
Joe Hershberger6b96c1a2016-06-10 14:53:32 -05001224
Simon Glassb2e83c62021-12-18 14:54:31 -07001225 if args.defconfigs:
1226 defconfigs = get_matched_defconfigs(args.defconfigs)
Joe Hershberger91040e82015-05-19 13:21:19 -05001227 else:
Masahiro Yamada684c3062016-07-25 19:15:28 +09001228 defconfigs = get_all_defconfigs()
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001229
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +09001230 progress = Progress(len(defconfigs))
Simon Glassb2e83c62021-12-18 14:54:31 -07001231 slots = Slots(toolchains, configs, args, progress, reference_src_dir,
Simon Glass6821a742017-07-10 14:47:47 -06001232 db_queue)
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001233
1234 # Main loop to process defconfig files:
1235 # Add a new subprocess into a vacant slot.
1236 # Sleep if there is no available slot.
Masahiro Yamadac5e60fd2016-05-19 15:51:55 +09001237 for defconfig in defconfigs:
1238 while not slots.add(defconfig):
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001239 while not slots.available():
1240 # No available slot: sleep for a while
1241 time.sleep(SLEEP_TIME)
1242
1243 # wait until all the subprocesses finish
1244 while not slots.empty():
1245 time.sleep(SLEEP_TIME)
1246
Simon Glass793dca32019-10-31 07:42:57 -06001247 print('')
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001248 slots.show_failed_boards()
Masahiro Yamadafc2661e2016-06-15 14:33:54 +09001249 slots.show_suspicious_boards()
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001250
Simon Glasscb008832017-06-15 21:39:33 -06001251def find_kconfig_rules(kconf, config, imply_config):
1252 """Check whether a config has a 'select' or 'imply' keyword
1253
1254 Args:
Tom Rini65e05dd2019-09-20 17:42:09 -04001255 kconf: Kconfiglib.Kconfig object
Simon Glasscb008832017-06-15 21:39:33 -06001256 config: Name of config to check (without CONFIG_ prefix)
1257 imply_config: Implying config (without CONFIG_ prefix) which may or
1258 may not have an 'imply' for 'config')
1259
1260 Returns:
1261 Symbol object for 'config' if found, else None
1262 """
Tom Rini65e05dd2019-09-20 17:42:09 -04001263 sym = kconf.syms.get(imply_config)
Simon Glasscb008832017-06-15 21:39:33 -06001264 if sym:
Simon Glassea40b202021-07-21 21:35:53 -06001265 for sel, cond in (sym.selects + sym.implies):
Simon Glassa3627082021-12-18 08:09:42 -07001266 if sel.name == config:
Simon Glasscb008832017-06-15 21:39:33 -06001267 return sym
1268 return None
1269
1270def check_imply_rule(kconf, config, imply_config):
1271 """Check if we can add an 'imply' option
1272
1273 This finds imply_config in the Kconfig and looks to see if it is possible
1274 to add an 'imply' for 'config' to that part of the Kconfig.
1275
1276 Args:
Tom Rini65e05dd2019-09-20 17:42:09 -04001277 kconf: Kconfiglib.Kconfig object
Simon Glasscb008832017-06-15 21:39:33 -06001278 config: Name of config to check (without CONFIG_ prefix)
1279 imply_config: Implying config (without CONFIG_ prefix) which may or
1280 may not have an 'imply' for 'config')
1281
1282 Returns:
1283 tuple:
1284 filename of Kconfig file containing imply_config, or None if none
1285 line number within the Kconfig file, or 0 if none
1286 message indicating the result
1287 """
Tom Rini65e05dd2019-09-20 17:42:09 -04001288 sym = kconf.syms.get(imply_config)
Simon Glasscb008832017-06-15 21:39:33 -06001289 if not sym:
1290 return 'cannot find sym'
Simon Glassea40b202021-07-21 21:35:53 -06001291 nodes = sym.nodes
1292 if len(nodes) != 1:
1293 return '%d locations' % len(nodes)
Simon Glassa3627082021-12-18 08:09:42 -07001294 node = nodes[0]
1295 fname, linenum = node.filename, node.linenr
Simon Glasscb008832017-06-15 21:39:33 -06001296 cwd = os.getcwd()
1297 if cwd and fname.startswith(cwd):
1298 fname = fname[len(cwd) + 1:]
1299 file_line = ' at %s:%d' % (fname, linenum)
1300 with open(fname) as fd:
1301 data = fd.read().splitlines()
1302 if data[linenum - 1] != 'config %s' % imply_config:
1303 return None, 0, 'bad sym format %s%s' % (data[linenum], file_line)
1304 return fname, linenum, 'adding%s' % file_line
1305
1306def add_imply_rule(config, fname, linenum):
1307 """Add a new 'imply' option to a Kconfig
1308
1309 Args:
1310 config: config option to add an imply for (without CONFIG_ prefix)
1311 fname: Kconfig filename to update
1312 linenum: Line number to place the 'imply' before
1313
1314 Returns:
1315 Message indicating the result
1316 """
1317 file_line = ' at %s:%d' % (fname, linenum)
1318 data = open(fname).read().splitlines()
1319 linenum -= 1
1320
1321 for offset, line in enumerate(data[linenum:]):
1322 if line.strip().startswith('help') or not line:
1323 data.insert(linenum + offset, '\timply %s' % config)
Simon Glass2fd85bd2021-12-18 14:54:33 -07001324 write_file(fname, data)
Simon Glasscb008832017-06-15 21:39:33 -06001325 return 'added%s' % file_line
1326
1327 return 'could not insert%s'
1328
1329(IMPLY_MIN_2, IMPLY_TARGET, IMPLY_CMD, IMPLY_NON_ARCH_BOARD) = (
1330 1, 2, 4, 8)
Simon Glass9b2a2e82017-06-15 21:39:32 -06001331
1332IMPLY_FLAGS = {
1333 'min2': [IMPLY_MIN_2, 'Show options which imply >2 boards (normally >5)'],
1334 'target': [IMPLY_TARGET, 'Allow CONFIG_TARGET_... options to imply'],
1335 'cmd': [IMPLY_CMD, 'Allow CONFIG_CMD_... to imply'],
Simon Glasscb008832017-06-15 21:39:33 -06001336 'non-arch-board': [
1337 IMPLY_NON_ARCH_BOARD,
1338 'Allow Kconfig options outside arch/ and /board/ to imply'],
Simon Glass9b2a2e82017-06-15 21:39:32 -06001339};
1340
Simon Glass9d603392021-12-18 08:09:43 -07001341
1342def read_database():
1343 """Read in the config database
1344
1345 Returns:
1346 tuple:
1347 set of all config options seen (each a str)
1348 set of all defconfigs seen (each a str)
1349 dict of configs for each defconfig:
1350 key: defconfig name, e.g. "MPC8548CDS_legacy_defconfig"
1351 value: dict:
1352 key: CONFIG option
1353 value: Value of option
1354 dict of defconfigs for each config:
1355 key: CONFIG option
1356 value: set of boards using that option
1357
1358 """
1359 configs = {}
1360
1361 # key is defconfig name, value is dict of (CONFIG_xxx, value)
1362 config_db = {}
1363
1364 # Set of all config options we have seen
1365 all_configs = set()
1366
1367 # Set of all defconfigs we have seen
1368 all_defconfigs = set()
1369
1370 defconfig_db = collections.defaultdict(set)
1371 with open(CONFIG_DATABASE) as fd:
1372 for line in fd.readlines():
1373 line = line.rstrip()
1374 if not line: # Separator between defconfigs
1375 config_db[defconfig] = configs
1376 all_defconfigs.add(defconfig)
1377 configs = {}
1378 elif line[0] == ' ': # CONFIG line
1379 config, value = line.strip().split('=', 1)
1380 configs[config] = value
1381 defconfig_db[config].add(defconfig)
1382 all_configs.add(config)
1383 else: # New defconfig
1384 defconfig = line
1385
1386 return all_configs, all_defconfigs, config_db, defconfig_db
1387
1388
Simon Glasscb008832017-06-15 21:39:33 -06001389def do_imply_config(config_list, add_imply, imply_flags, skip_added,
1390 check_kconfig=True, find_superset=False):
Simon Glass99b66602017-06-01 19:39:03 -06001391 """Find CONFIG options which imply those in the list
1392
1393 Some CONFIG options can be implied by others and this can help to reduce
1394 the size of the defconfig files. For example, CONFIG_X86 implies
1395 CONFIG_CMD_IRQ, so we can put 'imply CMD_IRQ' under 'config X86' and
1396 all x86 boards will have that option, avoiding adding CONFIG_CMD_IRQ to
1397 each of the x86 defconfig files.
1398
1399 This function uses the moveconfig database to find such options. It
1400 displays a list of things that could possibly imply those in the list.
1401 The algorithm ignores any that start with CONFIG_TARGET since these
1402 typically refer to only a few defconfigs (often one). It also does not
1403 display a config with less than 5 defconfigs.
1404
1405 The algorithm works using sets. For each target config in config_list:
1406 - Get the set 'defconfigs' which use that target config
1407 - For each config (from a list of all configs):
1408 - Get the set 'imply_defconfig' of defconfigs which use that config
1409 -
1410 - If imply_defconfigs contains anything not in defconfigs then
1411 this config does not imply the target config
1412
1413 Params:
1414 config_list: List of CONFIG options to check (each a string)
Simon Glasscb008832017-06-15 21:39:33 -06001415 add_imply: Automatically add an 'imply' for each config.
Simon Glass9b2a2e82017-06-15 21:39:32 -06001416 imply_flags: Flags which control which implying configs are allowed
1417 (IMPLY_...)
Simon Glasscb008832017-06-15 21:39:33 -06001418 skip_added: Don't show options which already have an imply added.
1419 check_kconfig: Check if implied symbols already have an 'imply' or
1420 'select' for the target config, and show this information if so.
Simon Glass99b66602017-06-01 19:39:03 -06001421 find_superset: True to look for configs which are a superset of those
1422 already found. So for example if CONFIG_EXYNOS5 implies an option,
1423 but CONFIG_EXYNOS covers a larger set of defconfigs and also
1424 implies that option, this will drop the former in favour of the
1425 latter. In practice this option has not proved very used.
1426
1427 Note the terminoloy:
1428 config - a CONFIG_XXX options (a string, e.g. 'CONFIG_CMD_EEPROM')
1429 defconfig - a defconfig file (a string, e.g. 'configs/snow_defconfig')
1430 """
Simon Glasscb008832017-06-15 21:39:33 -06001431 kconf = KconfigScanner().conf if check_kconfig else None
1432 if add_imply and add_imply != 'all':
Simon Glassa3627082021-12-18 08:09:42 -07001433 add_imply = add_imply.split(',')
Simon Glasscb008832017-06-15 21:39:33 -06001434
Simon Glass9d603392021-12-18 08:09:43 -07001435 all_configs, all_defconfigs, config_db, defconfig_db = read_database()
Simon Glass99b66602017-06-01 19:39:03 -06001436
Simon Glassa3627082021-12-18 08:09:42 -07001437 # Work through each target config option in turn, independently
Simon Glass99b66602017-06-01 19:39:03 -06001438 for config in config_list:
1439 defconfigs = defconfig_db.get(config)
1440 if not defconfigs:
Simon Glass793dca32019-10-31 07:42:57 -06001441 print('%s not found in any defconfig' % config)
Simon Glass99b66602017-06-01 19:39:03 -06001442 continue
1443
1444 # Get the set of defconfigs without this one (since a config cannot
1445 # imply itself)
1446 non_defconfigs = all_defconfigs - defconfigs
1447 num_defconfigs = len(defconfigs)
Simon Glass793dca32019-10-31 07:42:57 -06001448 print('%s found in %d/%d defconfigs' % (config, num_defconfigs,
1449 len(all_configs)))
Simon Glass99b66602017-06-01 19:39:03 -06001450
1451 # This will hold the results: key=config, value=defconfigs containing it
1452 imply_configs = {}
1453 rest_configs = all_configs - set([config])
1454
1455 # Look at every possible config, except the target one
1456 for imply_config in rest_configs:
Simon Glass9b2a2e82017-06-15 21:39:32 -06001457 if 'ERRATUM' in imply_config:
Simon Glass99b66602017-06-01 19:39:03 -06001458 continue
Simon Glass9b2a2e82017-06-15 21:39:32 -06001459 if not (imply_flags & IMPLY_CMD):
1460 if 'CONFIG_CMD' in imply_config:
1461 continue
1462 if not (imply_flags & IMPLY_TARGET):
1463 if 'CONFIG_TARGET' in imply_config:
1464 continue
Simon Glass99b66602017-06-01 19:39:03 -06001465
1466 # Find set of defconfigs that have this config
1467 imply_defconfig = defconfig_db[imply_config]
1468
1469 # Get the intersection of this with defconfigs containing the
1470 # target config
1471 common_defconfigs = imply_defconfig & defconfigs
1472
1473 # Get the set of defconfigs containing this config which DO NOT
1474 # also contain the taret config. If this set is non-empty it means
1475 # that this config affects other defconfigs as well as (possibly)
1476 # the ones affected by the target config. This means it implies
1477 # things we don't want to imply.
1478 not_common_defconfigs = imply_defconfig & non_defconfigs
1479 if not_common_defconfigs:
1480 continue
1481
1482 # If there are common defconfigs, imply_config may be useful
1483 if common_defconfigs:
1484 skip = False
1485 if find_superset:
Simon Glass793dca32019-10-31 07:42:57 -06001486 for prev in list(imply_configs.keys()):
Simon Glass99b66602017-06-01 19:39:03 -06001487 prev_count = len(imply_configs[prev])
1488 count = len(common_defconfigs)
1489 if (prev_count > count and
1490 (imply_configs[prev] & common_defconfigs ==
1491 common_defconfigs)):
1492 # skip imply_config because prev is a superset
1493 skip = True
1494 break
1495 elif count > prev_count:
1496 # delete prev because imply_config is a superset
1497 del imply_configs[prev]
1498 if not skip:
1499 imply_configs[imply_config] = common_defconfigs
1500
1501 # Now we have a dict imply_configs of configs which imply each config
1502 # The value of each dict item is the set of defconfigs containing that
1503 # config. Rank them so that we print the configs that imply the largest
1504 # number of defconfigs first.
Simon Glasscb008832017-06-15 21:39:33 -06001505 ranked_iconfigs = sorted(imply_configs,
Simon Glass99b66602017-06-01 19:39:03 -06001506 key=lambda k: len(imply_configs[k]), reverse=True)
Simon Glasscb008832017-06-15 21:39:33 -06001507 kconfig_info = ''
1508 cwd = os.getcwd()
1509 add_list = collections.defaultdict(list)
1510 for iconfig in ranked_iconfigs:
1511 num_common = len(imply_configs[iconfig])
Simon Glass99b66602017-06-01 19:39:03 -06001512
1513 # Don't bother if there are less than 5 defconfigs affected.
Simon Glass9b2a2e82017-06-15 21:39:32 -06001514 if num_common < (2 if imply_flags & IMPLY_MIN_2 else 5):
Simon Glass99b66602017-06-01 19:39:03 -06001515 continue
Simon Glasscb008832017-06-15 21:39:33 -06001516 missing = defconfigs - imply_configs[iconfig]
Simon Glass99b66602017-06-01 19:39:03 -06001517 missing_str = ', '.join(missing) if missing else 'all'
1518 missing_str = ''
Simon Glasscb008832017-06-15 21:39:33 -06001519 show = True
1520 if kconf:
1521 sym = find_kconfig_rules(kconf, config[CONFIG_LEN:],
1522 iconfig[CONFIG_LEN:])
1523 kconfig_info = ''
1524 if sym:
Simon Glassea40b202021-07-21 21:35:53 -06001525 nodes = sym.nodes
1526 if len(nodes) == 1:
1527 fname, linenum = nodes[0].filename, nodes[0].linenr
Simon Glasscb008832017-06-15 21:39:33 -06001528 if cwd and fname.startswith(cwd):
1529 fname = fname[len(cwd) + 1:]
1530 kconfig_info = '%s:%d' % (fname, linenum)
1531 if skip_added:
1532 show = False
1533 else:
Tom Rini65e05dd2019-09-20 17:42:09 -04001534 sym = kconf.syms.get(iconfig[CONFIG_LEN:])
Simon Glasscb008832017-06-15 21:39:33 -06001535 fname = ''
1536 if sym:
Simon Glassea40b202021-07-21 21:35:53 -06001537 nodes = sym.nodes
1538 if len(nodes) == 1:
1539 fname, linenum = nodes[0].filename, nodes[0].linenr
Simon Glasscb008832017-06-15 21:39:33 -06001540 if cwd and fname.startswith(cwd):
1541 fname = fname[len(cwd) + 1:]
1542 in_arch_board = not sym or (fname.startswith('arch') or
1543 fname.startswith('board'))
1544 if (not in_arch_board and
1545 not (imply_flags & IMPLY_NON_ARCH_BOARD)):
1546 continue
1547
1548 if add_imply and (add_imply == 'all' or
1549 iconfig in add_imply):
1550 fname, linenum, kconfig_info = (check_imply_rule(kconf,
1551 config[CONFIG_LEN:], iconfig[CONFIG_LEN:]))
1552 if fname:
1553 add_list[fname].append(linenum)
1554
1555 if show and kconfig_info != 'skip':
Simon Glass793dca32019-10-31 07:42:57 -06001556 print('%5d : %-30s%-25s %s' % (num_common, iconfig.ljust(30),
1557 kconfig_info, missing_str))
Simon Glasscb008832017-06-15 21:39:33 -06001558
1559 # Having collected a list of things to add, now we add them. We process
1560 # each file from the largest line number to the smallest so that
1561 # earlier additions do not affect our line numbers. E.g. if we added an
1562 # imply at line 20 it would change the position of each line after
1563 # that.
Simon Glass793dca32019-10-31 07:42:57 -06001564 for fname, linenums in add_list.items():
Simon Glasscb008832017-06-15 21:39:33 -06001565 for linenum in sorted(linenums, reverse=True):
1566 add_imply_rule(config[CONFIG_LEN:], fname, linenum)
Simon Glass99b66602017-06-01 19:39:03 -06001567
1568
Simon Glass65d7fce2021-12-18 08:09:46 -07001569def do_find_config(config_list):
1570 """Find boards with a given combination of CONFIGs
1571
1572 Params:
1573 config_list: List of CONFIG options to check (each a string consisting
1574 of a config option, with or without a CONFIG_ prefix. If an option
1575 is preceded by a tilde (~) then it must be false, otherwise it must
1576 be true)
1577 """
1578 all_configs, all_defconfigs, config_db, defconfig_db = read_database()
1579
1580 # Get the whitelist
1581 with open('scripts/config_whitelist.txt') as inf:
1582 adhoc_configs = set(inf.read().splitlines())
1583
1584 # Start with all defconfigs
1585 out = all_defconfigs
1586
1587 # Work through each config in turn
1588 adhoc = []
1589 for item in config_list:
1590 # Get the real config name and whether we want this config or not
1591 cfg = item
1592 want = True
1593 if cfg[0] == '~':
1594 want = False
1595 cfg = cfg[1:]
1596
1597 if cfg in adhoc_configs:
1598 adhoc.append(cfg)
1599 continue
1600
1601 # Search everything that is still in the running. If it has a config
1602 # that we want, or doesn't have one that we don't, add it into the
1603 # running for the next stage
1604 in_list = out
1605 out = set()
1606 for defc in in_list:
1607 has_cfg = cfg in config_db[defc]
1608 if has_cfg == want:
1609 out.add(defc)
1610 if adhoc:
1611 print(f"Error: Not in Kconfig: %s" % ' '.join(adhoc))
1612 else:
1613 print(f'{len(out)} matches')
1614 print(' '.join(out))
1615
1616
1617def prefix_config(cfg):
1618 """Prefix a config with CONFIG_ if needed
1619
1620 This handles ~ operator, which indicates that the CONFIG should be disabled
1621
1622 >>> prefix_config('FRED')
1623 'CONFIG_FRED'
1624 >>> prefix_config('CONFIG_FRED')
1625 'CONFIG_FRED'
1626 >>> prefix_config('~FRED')
1627 '~CONFIG_FRED'
1628 >>> prefix_config('~CONFIG_FRED')
1629 '~CONFIG_FRED'
1630 >>> prefix_config('A123')
1631 'CONFIG_A123'
1632 """
1633 op = ''
1634 if cfg[0] == '~':
1635 op = cfg[0]
1636 cfg = cfg[1:]
1637 if not cfg.startswith('CONFIG_'):
1638 cfg = 'CONFIG_' + cfg
1639 return op + cfg
1640
1641
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001642def main():
1643 try:
1644 cpu_count = multiprocessing.cpu_count()
1645 except NotImplementedError:
1646 cpu_count = 1
1647
Simon Glassb2e83c62021-12-18 14:54:31 -07001648 epilog = '''Move config options from headers to defconfig files. See
1649doc/develop/moveconfig.rst for documentation.'''
1650
1651 parser = ArgumentParser(epilog=epilog)
1652 # Add arguments here
1653 parser.add_argument('-a', '--add-imply', type=str, default='',
Simon Glasscb008832017-06-15 21:39:33 -06001654 help='comma-separated list of CONFIG options to add '
1655 "an 'imply' statement to for the CONFIG in -i")
Simon Glassb2e83c62021-12-18 14:54:31 -07001656 parser.add_argument('-A', '--skip-added', action='store_true', default=False,
Simon Glasscb008832017-06-15 21:39:33 -06001657 help="don't show options which are already marked as "
1658 'implying others')
Simon Glassb2e83c62021-12-18 14:54:31 -07001659 parser.add_argument('-b', '--build-db', action='store_true', default=False,
Simon Glassd73fcb12017-06-01 19:39:02 -06001660 help='build a CONFIG database')
Simon Glassb2e83c62021-12-18 14:54:31 -07001661 parser.add_argument('-c', '--color', action='store_true', default=False,
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001662 help='display the log in color')
Simon Glassb2e83c62021-12-18 14:54:31 -07001663 parser.add_argument('-C', '--commit', action='store_true', default=False,
Simon Glass9ede2122016-09-12 23:18:21 -06001664 help='Create a git commit for the operation')
Simon Glassb2e83c62021-12-18 14:54:31 -07001665 parser.add_argument('-d', '--defconfigs', type=str,
Simon Glassee4e61b2017-06-01 19:38:59 -06001666 help='a file containing a list of defconfigs to move, '
1667 "one per line (for example 'snow_defconfig') "
1668 "or '-' to read from stdin")
Simon Glassb2e83c62021-12-18 14:54:31 -07001669 parser.add_argument('-e', '--exit-on-error', action='store_true',
Simon Glasse1ae5632021-12-18 08:09:44 -07001670 default=False,
1671 help='exit immediately on any error')
Simon Glassb2e83c62021-12-18 14:54:31 -07001672 parser.add_argument('-f', '--find', action='store_true', default=False,
Simon Glass65d7fce2021-12-18 08:09:46 -07001673 help='Find boards with a given config combination')
Simon Glassb2e83c62021-12-18 14:54:31 -07001674 parser.add_argument('-H', '--headers-only', dest='cleanup_headers_only',
Simon Glasse1ae5632021-12-18 08:09:44 -07001675 action='store_true', default=False,
1676 help='only cleanup the headers')
Simon Glassb2e83c62021-12-18 14:54:31 -07001677 parser.add_argument('-i', '--imply', action='store_true', default=False,
Simon Glass99b66602017-06-01 19:39:03 -06001678 help='find options which imply others')
Simon Glassb2e83c62021-12-18 14:54:31 -07001679 parser.add_argument('-I', '--imply-flags', type=str, default='',
Simon Glass9b2a2e82017-06-15 21:39:32 -06001680 help="control the -i option ('help' for help")
Simon Glassb2e83c62021-12-18 14:54:31 -07001681 parser.add_argument('-j', '--jobs', type=int, default=cpu_count,
Simon Glasse1ae5632021-12-18 08:09:44 -07001682 help='the number of jobs to run simultaneously')
Simon Glassb2e83c62021-12-18 14:54:31 -07001683 parser.add_argument('-n', '--dry-run', action='store_true', default=False,
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001684 help='perform a trial run (show log with no changes)')
Simon Glassb2e83c62021-12-18 14:54:31 -07001685 parser.add_argument('-r', '--git-ref', type=str,
Simon Glasse1ae5632021-12-18 08:09:44 -07001686 help='the git ref to clone for building the autoconf.mk')
Simon Glassb2e83c62021-12-18 14:54:31 -07001687 parser.add_argument('-s', '--force-sync', action='store_true', default=False,
Masahiro Yamada8513dc02016-05-19 15:52:08 +09001688 help='force sync by savedefconfig')
Simon Glassb2e83c62021-12-18 14:54:31 -07001689 parser.add_argument('-S', '--spl', action='store_true', default=False,
Masahiro Yamada07913d12016-08-22 22:18:22 +09001690 help='parse config options defined for SPL build')
Simon Glassb2e83c62021-12-18 14:54:31 -07001691 parser.add_argument('-t', '--test', action='store_true', default=False,
Simon Glasse1ae5632021-12-18 08:09:44 -07001692 help='run unit tests')
Simon Glassb2e83c62021-12-18 14:54:31 -07001693 parser.add_argument('-y', '--yes', action='store_true', default=False,
Simon Glass6b403df2016-09-12 23:18:20 -06001694 help="respond 'yes' to any prompts")
Simon Glassb2e83c62021-12-18 14:54:31 -07001695 parser.add_argument('-v', '--verbose', action='store_true', default=False,
Joe Hershberger95bf9c72015-05-19 13:21:24 -05001696 help='show any build errors as boards are built')
Simon Glassb2e83c62021-12-18 14:54:31 -07001697 parser.add_argument('configs', nargs='*')
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001698
Simon Glassb2e83c62021-12-18 14:54:31 -07001699 args = parser.parse_args()
1700 configs = args.configs
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001701
Simon Glassb2e83c62021-12-18 14:54:31 -07001702 if args.test:
Simon Glass84067a52021-12-18 08:09:45 -07001703 sys.argv = [sys.argv[0]]
1704 fail, count = doctest.testmod()
1705 if fail:
1706 return 1
1707 unittest.main()
1708
Simon Glassb2e83c62021-12-18 14:54:31 -07001709 if not any((len(configs), args.force_sync, args.build_db, args.imply,
1710 args.find)):
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001711 parser.print_usage()
1712 sys.exit(1)
1713
Masahiro Yamadab6ef3932016-05-19 15:51:58 +09001714 # prefix the option name with CONFIG_ if missing
Simon Glass65d7fce2021-12-18 08:09:46 -07001715 configs = [prefix_config(cfg) for cfg in configs]
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001716
Joe Hershberger2144f882015-05-19 13:21:20 -05001717 check_top_directory()
1718
Simon Glassb2e83c62021-12-18 14:54:31 -07001719 if args.imply:
Simon Glass9b2a2e82017-06-15 21:39:32 -06001720 imply_flags = 0
Simon Glassb2e83c62021-12-18 14:54:31 -07001721 if args.imply_flags == 'all':
Simon Glassdee36c72017-07-10 14:47:46 -06001722 imply_flags = -1
1723
Simon Glassb2e83c62021-12-18 14:54:31 -07001724 elif args.imply_flags:
1725 for flag in args.imply_flags.split(','):
Simon Glassdee36c72017-07-10 14:47:46 -06001726 bad = flag not in IMPLY_FLAGS
1727 if bad:
Simon Glass793dca32019-10-31 07:42:57 -06001728 print("Invalid flag '%s'" % flag)
Simon Glassdee36c72017-07-10 14:47:46 -06001729 if flag == 'help' or bad:
Simon Glass793dca32019-10-31 07:42:57 -06001730 print("Imply flags: (separate with ',')")
1731 for name, info in IMPLY_FLAGS.items():
1732 print(' %-15s: %s' % (name, info[1]))
Simon Glassdee36c72017-07-10 14:47:46 -06001733 parser.print_usage()
1734 sys.exit(1)
1735 imply_flags |= IMPLY_FLAGS[flag][0]
Simon Glass9b2a2e82017-06-15 21:39:32 -06001736
Simon Glassb2e83c62021-12-18 14:54:31 -07001737 do_imply_config(configs, args.add_imply, imply_flags, args.skip_added)
Simon Glass99b66602017-06-01 19:39:03 -06001738 return
1739
Simon Glassb2e83c62021-12-18 14:54:31 -07001740 if args.find:
Simon Glass65d7fce2021-12-18 08:09:46 -07001741 do_find_config(configs)
1742 return
1743
Simon Glassd73fcb12017-06-01 19:39:02 -06001744 config_db = {}
Simon Glass793dca32019-10-31 07:42:57 -06001745 db_queue = queue.Queue()
Simon Glassd73fcb12017-06-01 19:39:02 -06001746 t = DatabaseThread(config_db, db_queue)
1747 t.setDaemon(True)
1748 t.start()
1749
Simon Glassb2e83c62021-12-18 14:54:31 -07001750 if not args.cleanup_headers_only:
Masahiro Yamadaf7536f72016-07-25 19:15:23 +09001751 check_clean_directory()
Simon Glass793dca32019-10-31 07:42:57 -06001752 bsettings.Setup('')
Simon Glass6821a742017-07-10 14:47:47 -06001753 toolchains = toolchain.Toolchains()
1754 toolchains.GetSettings()
1755 toolchains.Scan(verbose=False)
Simon Glassb2e83c62021-12-18 14:54:31 -07001756 move_config(toolchains, configs, args, db_queue)
Simon Glassd73fcb12017-06-01 19:39:02 -06001757 db_queue.join()
Joe Hershberger2144f882015-05-19 13:21:20 -05001758
Masahiro Yamada6a9f79f2016-05-19 15:52:09 +09001759 if configs:
Simon Glassb2e83c62021-12-18 14:54:31 -07001760 cleanup_headers(configs, args)
1761 cleanup_extra_options(configs, args)
1762 cleanup_whitelist(configs, args)
1763 cleanup_readme(configs, args)
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001764
Simon Glassb2e83c62021-12-18 14:54:31 -07001765 if args.commit:
Simon Glass9ede2122016-09-12 23:18:21 -06001766 subprocess.call(['git', 'add', '-u'])
1767 if configs:
1768 msg = 'Convert %s %sto Kconfig' % (configs[0],
1769 'et al ' if len(configs) > 1 else '')
1770 msg += ('\n\nThis converts the following to Kconfig:\n %s\n' %
1771 '\n '.join(configs))
1772 else:
1773 msg = 'configs: Resync with savedefconfig'
1774 msg += '\n\nRsync all defconfig files using moveconfig.py'
1775 subprocess.call(['git', 'commit', '-s', '-m', msg])
1776
Simon Glassb2e83c62021-12-18 14:54:31 -07001777 if args.build_db:
Simon Glassd73fcb12017-06-01 19:39:02 -06001778 with open(CONFIG_DATABASE, 'w') as fd:
Simon Glass793dca32019-10-31 07:42:57 -06001779 for defconfig, configs in config_db.items():
Simon Glassc79d18c2017-08-13 16:02:54 -06001780 fd.write('%s\n' % defconfig)
Simon Glassd73fcb12017-06-01 19:39:02 -06001781 for config in sorted(configs.keys()):
Simon Glassc79d18c2017-08-13 16:02:54 -06001782 fd.write(' %s=%s\n' % (config, configs[config]))
1783 fd.write('\n')
Simon Glassd73fcb12017-06-01 19:39:02 -06001784
Masahiro Yamada5a27c732015-05-20 11:36:07 +09001785if __name__ == '__main__':
Simon Glass65d7fce2021-12-18 08:09:46 -07001786 sys.exit(main())