summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabriel Ganne <gabriel.ganne@enea.com>2018-02-20 12:07:36 +0100
committerRichard Braun <rbraun@sceen.net>2018-02-24 16:53:44 +0100
commited0001727225b9acd84420156d3b18820c7a11f5 (patch)
treef6da4a8204cbf343596f63bc9d32ade98f1a8f5d
parentc0aa1dd1915d89dbdacb1265f48ed83ebc02708d (diff)
tools/build_configs.py: improve pep8 and pylint compliance
pep8 fixes: * remove whitespaces in dict declarations (E203 whitespace before ':') * two blank lines between functions (E302 expected 2 blank lines, found 1) * no spaces in set function arguments (E251 unexpected spaces around keyword / parameter equals) pylint fixes: * rename some variables to fix some redefined-outer-name warnings passing <- passing_filters_list blocking <- blocking_filters_list * explicit config file name (invalid-name warning) * fix many map/filter deprecated-lambda warnings [1] eg. for values as below, replace map/lambda by comprehension as follow # values = [1, 2, 3] # doubles = map(lambda x: x * 2, values) # doubles = [x * 2 for x in values] * un-name some unused variables with '_' to silence unused-variable eg. # for used_val_1, used_val_2 in my_list: # ... # for used_val_1, _ in my_list: [1] https://docs.quantifiedcode.com/python-anti-patterns/readability/using_map_or_filter_where_list_comprehension_is_possible.html
-rwxr-xr-xtools/build_configs.py209
1 files changed, 120 insertions, 89 deletions
diff --git a/tools/build_configs.py b/tools/build_configs.py
index b44c77b..cd71459 100755
--- a/tools/build_configs.py
+++ b/tools/build_configs.py
@@ -1,11 +1,13 @@
#!/usr/bin/env python
-#
-# Generate a large number of valid configurations, build them concurrently,
-# and report.
+'''
+Configuration builder.
+
+Generate a large number of valid configurations, build them concurrently,
+and report.
+'''
from __future__ import print_function
-import argparse
import itertools
import multiprocessing
import os
@@ -15,9 +17,13 @@ import subprocess
import sys
import tempfile
+from argparse import Action, ArgumentParser, RawDescriptionHelpFormatter
+
+
def print_fn(*args):
- map(sys.stdout.write, args + tuple('\n'))
- return None
+ for arg in args:
+ print(arg)
+
def quote_if_needed(value):
if not value.isdigit() and value != 'y' and value != 'n':
@@ -25,24 +31,30 @@ def quote_if_needed(value):
return value
-# Generate a list of all possible combinations of options.
+
def gen_configs_list(options_dict):
+ 'Generate a list of all possible combinations of options.'
names = options_dict.keys()
product = itertools.product(*options_dict.values())
- return map(lambda x: dict(zip(names, x)), product)
+ return [dict(zip(names, x)) for x in product]
+
-# Generate a list of all possible combinations of options as strings.
def gen_configs_values_str(options_dict):
- return map(lambda x: ' '.join(x.values()), gen_configs_list(options_dict))
+ 'Generate a list of all possible combinations of options as strings.'
+ return [' '.join(x.values()) for x in gen_configs_list(options_dict)]
+
-# Does the same as gen_configs_values_str() but adds the -Werror option
-# to all generated strings.
def gen_cc_options_list(options_dict):
- return map(lambda x: '%s -Werror' % x, gen_configs_values_str(options_dict))
+ '''
+ Does the same as gen_configs_values_str() but adds the -Werror option
+ to all generated strings.
+ '''
+ return ['{} -Werror'.format(x) for x in gen_configs_values_str(options_dict)]
+
def gen_exclusive_boolean_filter(args):
enabled_option, options_list = args
- filter = dict()
+ option_filter = dict()
for option in options_list:
if option == enabled_option:
@@ -50,24 +62,28 @@ def gen_exclusive_boolean_filter(args):
else:
value = [True, 'n']
- filter.update({option : value})
+ option_filter.update({option: value})
+
+ return option_filter
- return filter
-# Generate a list of passing filters on a list of boolean options.
-#
-# The resulting filters match configurations that have only one of the given
-# options enabled, unless all_disabled is true, in which case an additional
-# filter is generated to match configurations where none of the options
-# are enabled.
def gen_exclusive_boolean_filters_list(options_list, all_disabled=False):
- option_and_options = list(map(lambda x: (x, options_list), options_list))
+ '''
+ Generate a list of passing filters on a list of boolean options.
+
+ The resulting filters match configurations that have only one of the given
+ options enabled, unless all_disabled is true, in which case an additional
+ filter is generated to match configurations where none of the options
+ are enabled.
+ '''
+ option_and_options = [(x, options_list) for x in options_list]
if all_disabled:
option_and_options.append((None, options_list))
return list(map(gen_exclusive_boolean_filter, option_and_options))
+
# Dictionary of compiler options.
#
# Each entry describes a single compiler option. The key is mostly ignored
@@ -75,9 +91,9 @@ def gen_exclusive_boolean_filters_list(options_list, all_disabled=False):
# gen_configs_list() function. The value is a list of all values that may
# be used for this compiler option when building a configuration.
all_cc_options_dict = {
- 'O' : ['-O0', '-O2', '-Os'],
- 'LTO' : ['-flto', '-fno-lto'],
- 'SSP' : ['-fno-stack-protector', '-fstack-protector'],
+ 'O': ['-O0', '-O2', '-Os'],
+ 'LTO': ['-flto', '-fno-lto'],
+ 'SSP': ['-fno-stack-protector', '-fstack-protector'],
}
# Dictionaries of options.
@@ -87,22 +103,22 @@ all_cc_options_dict = {
# option when building a configuration.
small_options_dict = {
- 'CONFIG_CC_OPTIONS' : gen_cc_options_list(all_cc_options_dict),
- 'CONFIG_SMP' : ['y', 'n'],
- 'CONFIG_MAX_CPUS' : ['1', '128'],
- 'CONFIG_ASSERT' : ['y', 'n'],
+ 'CONFIG_CC_OPTIONS': gen_cc_options_list(all_cc_options_dict),
+ 'CONFIG_SMP': ['y', 'n'],
+ 'CONFIG_MAX_CPUS': ['1', '128'],
+ 'CONFIG_ASSERT': ['y', 'n'],
}
large_options_dict = dict(small_options_dict)
large_options_dict.update({
- 'CONFIG_CC_EXE' : ['gcc', 'clang'],
- 'CONFIG_64BITS' : ['y', 'n'],
- 'CONFIG_X86_PAE' : ['y', 'n'],
- 'CONFIG_MUTEX_ADAPTIVE' : ['y', 'n'],
- 'CONFIG_MUTEX_PI' : ['y', 'n'],
- 'CONFIG_MUTEX_PLAIN' : ['y', 'n'],
- 'CONFIG_SHELL' : ['y', 'n'],
- 'CONFIG_THREAD_STACK_GUARD' : ['y', 'n'],
+ 'CONFIG_CC_EXE': ['gcc', 'clang'],
+ 'CONFIG_64BITS': ['y', 'n'],
+ 'CONFIG_X86_PAE': ['y', 'n'],
+ 'CONFIG_MUTEX_ADAPTIVE': ['y', 'n'],
+ 'CONFIG_MUTEX_PI': ['y', 'n'],
+ 'CONFIG_MUTEX_PLAIN': ['y', 'n'],
+ 'CONFIG_SHELL': ['y', 'n'],
+ 'CONFIG_THREAD_STACK_GUARD': ['y', 'n'],
})
test_list = [
@@ -120,12 +136,12 @@ test_list = [
test_options_dict = dict(small_options_dict)
for test in test_list:
- test_options_dict.update({test : ['y', 'n']})
+ test_options_dict.update({test: ['y', 'n']})
all_options_sets = {
- 'small' : small_options_dict,
- 'large' : large_options_dict,
- 'test' : test_options_dict,
+ 'small': small_options_dict,
+ 'large': large_options_dict,
+ 'test': test_options_dict,
}
# Filters.
@@ -149,51 +165,55 @@ passing_filters_list += gen_exclusive_boolean_filters_list(test_list,
blocking_filters_list = [
# XXX Clang currently cannot build the kernel with LTO.
{
- 'CONFIG_CC_EXE' : [True, 'clang'],
- 'CONFIG_CC_OPTIONS' : [True, re.compile('-flto')],
+ 'CONFIG_CC_EXE': [True, 'clang'],
+ 'CONFIG_CC_OPTIONS': [True, re.compile('-flto')],
},
{
- 'CONFIG_SMP' : [True, 'y'],
- 'CONFIG_MAX_CPUS' : [True, '1'],
+ 'CONFIG_SMP': [True, 'y'],
+ 'CONFIG_MAX_CPUS': [True, '1'],
},
{
- 'CONFIG_SMP' : [True, 'n'],
- 'CONFIG_MAX_CPUS' : [False, '1'],
+ 'CONFIG_SMP': [True, 'n'],
+ 'CONFIG_MAX_CPUS': [False, '1'],
},
{
- 'CONFIG_64BITS' : [True, 'y'],
- 'CONFIG_X86_PAE' : [True, 'y'],
+ 'CONFIG_64BITS': [True, 'y'],
+ 'CONFIG_X86_PAE': [True, 'y'],
},
]
+
def gen_config_line(config_entry):
name, value = config_entry
return '%s=%s\n' % (name, quote_if_needed(value))
+
def gen_config_content(config_dict):
return map(gen_config_line, config_dict.items())
+
def test_config_run(command, check, buildlog):
buildlog.writelines(['$ %s\n' % command])
buildlog.flush()
if check:
- return subprocess.check_call(command.split(), stdout = buildlog,
- stderr = subprocess.STDOUT)
+ return subprocess.check_call(command.split(), stdout=buildlog,
+ stderr=subprocess.STDOUT)
else:
- return subprocess.call(command.split(), stdout = buildlog,
- stderr = subprocess.STDOUT)
+ return subprocess.call(command.split(), stdout=buildlog,
+ stderr=subprocess.STDOUT)
+
-# This function is run in multiprocessing.Pool workers.
def test_config(args):
+ 'This function is run in multiprocessing.Pool workers.'
topbuilddir, config_dict = args
srctree = os.path.abspath(os.getcwd())
- buildtree = tempfile.mkdtemp(dir = topbuilddir)
+ buildtree = tempfile.mkdtemp(dir=topbuilddir)
os.chdir(buildtree)
buildlog = open('build.log', 'w')
- f = open('.testconfig', 'w')
- f.writelines(gen_config_content(config_dict))
- f.close()
+ config_file = open('.testconfig', 'w')
+ config_file.writelines(gen_config_content(config_dict))
+ config_file.close()
try:
test_config_run('%s/tools/kconfig/merge_config.sh'
@@ -217,10 +237,11 @@ def test_config(args):
return [retval, buildtree]
-# Return true if a filter completely matches a configuration.
+
def check_filter(config_dict, filter_dict):
+ 'Return true if a filter completely matches a configuration.'
for name, value in filter_dict.items():
- if not name in config_dict:
+ if name not in config_dict:
return False
if isinstance(value[1], str):
@@ -232,13 +253,15 @@ def check_filter(config_dict, filter_dict):
return True
+
def check_filter_relevant(config_dict, filter_dict):
- for name, value in filter_dict.items():
+ for name, _ in filter_dict.items():
if name in config_dict:
return True
return False
+
def check_filters_list_relevant(config_dict, filters_list):
for filter_dict in filters_list:
if check_filter_relevant(config_dict, filter_dict):
@@ -246,12 +269,15 @@ def check_filters_list_relevant(config_dict, filters_list):
return False
-# Return true if a configuration doesn't pass any given filter.
-#
-# If the given filters list is irrelevant, i.e. it applies to none of
-# the options in the given configuration, the filters are considered
-# to match.
+
def check_passing_filters(args):
+ '''
+ If the given filters list is irrelevant, i.e. it applies to none of
+ the options in the given configuration, the filters are considered
+ to match.
+
+ @return true if a configuration doesn't pass any given filter.
+ '''
config_dict, filters_list = args
if not check_filters_list_relevant(config_dict, filters_list):
@@ -263,8 +289,9 @@ def check_passing_filters(args):
return False
-# Return true if a configuration passes all the given filters.
+
def check_blocking_filters(args):
+ 'Return true if a configuration passes all the given filters.'
config_dict, filters_list = args
for filter_dict in filters_list:
@@ -273,29 +300,31 @@ def check_blocking_filters(args):
return True
-def filter_configs_list(configs_list, passing_filters_list,
- blocking_filters_list):
- configs_and_filters = map(lambda x: (x, passing_filters_list),
- configs_list)
- configs_list = map(lambda x: x[0], filter(check_passing_filters,
- configs_and_filters))
- configs_and_filters = map(lambda x: (x, blocking_filters_list),
- configs_list)
- configs_list = map(lambda x: x[0], filter(check_blocking_filters,
- configs_and_filters))
+
+def filter_configs_list(configs_list, passing, blocking):
+ configs_and_filters = [(x, passing) for x in configs_list]
+ configs_list = [x[0] for x in filter(check_passing_filters,
+ configs_and_filters)]
+ configs_and_filters = [(x, blocking) for x in configs_list]
+ configs_list = [x[0] for x in filter(check_blocking_filters,
+ configs_and_filters)]
return list(configs_list)
+
def find_options_dict(options_sets, name):
if name not in options_sets:
return None
return options_sets[name]
+
def print_set(name, options_dict):
print(name)
- map(lambda x: print_fn(' ' + x), sorted(iter(options_dict)))
+ for opt in sorted(iter(options_dict)):
+ print_fn(' ' + opt)
-class BuildConfigListSetsAction(argparse.Action):
+
+class BuildConfigListSetsAction(Action):
def __init__(self, nargs=0, **kwargs):
if nargs != 0:
raise ValueError("nargs not allowed")
@@ -303,12 +332,14 @@ class BuildConfigListSetsAction(argparse.Action):
super(BuildConfigListSetsAction, self).__init__(nargs=nargs, **kwargs)
def __call__(self, parser, namespace, values, option_string=None):
- map(print_set, all_options_sets.iterkeys(),
+ map(print_set, all_options_sets.keys(),
all_options_sets.values())
sys.exit(0)
+
def main():
- parser = argparse.ArgumentParser(description='Configuration builder')
+ parser = ArgumentParser(description=__doc__,
+ formatter_class=RawDescriptionHelpFormatter)
parser.add_argument('-s', '--set', default='small',
help='select a set of options (default=small)')
parser.add_argument('-l', '--list-sets', action=BuildConfigListSetsAction,
@@ -319,7 +350,7 @@ def main():
if not options_dict:
print('error: invalid set')
- sys.exit(2);
+ sys.exit(2)
print('set: {}'.format(args.set))
configs_list = filter_configs_list(gen_configs_list(options_dict),
@@ -331,11 +362,11 @@ def main():
# This tool performs out-of-tree builds and requires a clean source tree
print('cleaning source tree...')
subprocess.check_call(['make', 'distclean'])
- topbuilddir = os.path.abspath(tempfile.mkdtemp(prefix = 'build', dir = '.'))
+ topbuilddir = os.path.abspath(tempfile.mkdtemp(prefix='build', dir='.'))
print('top build directory: {}'.format(topbuilddir))
pool = multiprocessing.Pool()
- worker_args = map(lambda x: (topbuilddir, x), configs_list)
+ worker_args = [(topbuilddir, x) for x in configs_list]
try:
results = pool.map(test_config, worker_args)
@@ -345,10 +376,9 @@ def main():
shutil.rmtree(topbuilddir)
raise
- failures = list(filter(lambda x: x[0] != 0, results))
- map(lambda buildtree: print_fn('failed: %s/.config (%s/build.log)'
- % (buildtree, buildtree)),
- [buildtree for retval, buildtree in failures])
+ failures = [x for x in results if x[0] != 0]
+ for _, buildtree in failures:
+ print_fn('failed: {0}/.config ({0}/build.log)'.format(buildtree))
print('passed: {:d}'.format(nr_configs - len(failures)))
print('failed: {:d}'.format(len(failures)))
@@ -357,5 +387,6 @@ def main():
finally:
sys.exit(len(failures) != 0)
+
if __name__ == '__main__':
main()