diff options
author | Richard Braun <rbraun@sceen.net> | 2018-02-10 14:28:00 +0100 |
---|---|---|
committer | Richard Braun <rbraun@sceen.net> | 2018-02-12 21:10:00 +0100 |
commit | 9656d4234d97ec434d6efbcf1a33c53652faa9f2 (patch) | |
tree | a6d20288dbaa6cc2f64798e2df0e5818fbe3c025 | |
parent | ba782cb04a98bdccc4009c3abe272453daca501f (diff) |
tools/build_configs.py: implement passing filters
Reduce the complexity of generating exclusive boolean filters, in which
only one option can be enabled, by supporting passing filters, filtering
out configurations which do not match the filter.
-rwxr-xr-x | tools/build_configs.py | 136 |
1 files changed, 94 insertions, 42 deletions
diff --git a/tools/build_configs.py b/tools/build_configs.py index 132c1ef..1770e4b 100755 --- a/tools/build_configs.py +++ b/tools/build_configs.py @@ -38,25 +38,33 @@ def gen_configs_values_str(options_dict): def gen_cc_options_list(options_dict): return map(lambda x: '%s -Werror' % x, gen_configs_values_str(options_dict)) -# Check whether a filter prototype is valid. -# -# A filter prototype is a list of (name, value) pairs used to build a filter. -# Keep in mind that a valid filter must match invalid configurations. As a -# result, a filter prototype is valid if and only if -# - all options are included in the given list, and -# - the number of enabled options is not 1 -def check_exclusive_boolean_filter(prototype): - return (len(set(map(lambda x: x[0], prototype))) == len(prototype) - and len(filter(lambda x: x[1][1] == 'y', prototype)) != 1) - -# Generate a list of filters on a list of boolean options. +def gen_exclusive_boolean_filter(args): + enabled_option, options_list = args + filter = dict() + + for option in options_list: + if option == enabled_option: + value = [True, 'y'] + else: + value = [True, 'n'] + + filter.update({option : value}) + + return filter + +# Generate a list of passing filters on a list of boolean options. # -# The resulting filters match configurations that don't have one and only -# one of the given options enabled. -def gen_exclusive_boolean_filters_list(options_list): - product = itertools.product(options_list, [[True, 'y'], [True, 'n']]) - prototypes = list(itertools.combinations(product, len(options_list))) - return map(dict, filter(check_exclusive_boolean_filter, prototypes)) +# 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 = map(lambda x: (x, options_list), options_list) + + if all_disabled: + option_and_options += [(None, options_list)] + + return map(gen_exclusive_boolean_filter, option_and_options) # Dictionary of compiler options. # @@ -118,13 +126,25 @@ all_options_sets = { 'test' : test_options_dict, } -# List of filters used to determine valid configurations. +# Filters. # -# Each entry is a dictionary of options. The key matches an option name -# whereas the value is a [match_flag, string/regular expression] list. -# The match flag is true if the matching expression must match, false -# otherwise. -all_filters_list = [ +# A filter is a list of dictionaries of options. For each dictionary, the +# key matches an option name whereas the value is a +# [match_flag, string/regular expression] list. The match flag is true if +# the matching expression must match, false otherwise. +# +# Passing filters are used to allow configurations that match the filters, +# whereras blocking filters allow configurations that do not match. + +passing_filters_list = gen_exclusive_boolean_filters_list([ + 'CONFIG_MUTEX_ADAPTIVE', + 'CONFIG_MUTEX_PI', + 'CONFIG_MUTEX_PLAIN', +]) +passing_filters_list += gen_exclusive_boolean_filters_list(test_list, + all_disabled=True) + +blocking_filters_list = [ # XXX Clang currently cannot build the kernel with LTO. { 'CONFIG_CC_EXE' : [True, 'clang'], @@ -143,14 +163,6 @@ all_filters_list = [ 'CONFIG_X86_PAE' : [True, 'y'], }, ] -all_filters_list += gen_exclusive_boolean_filters_list([ - 'CONFIG_MUTEX_ADAPTIVE', - 'CONFIG_MUTEX_PI', - 'CONFIG_MUTEX_PLAIN' -]) - -# TODO Have both passing and blocking filters to reduce generation complexity. -all_filters_list += gen_exclusive_boolean_filters_list(test_list) def gen_config_line(config_entry): name, value = config_entry @@ -203,34 +215,73 @@ def test_config(args): return [retval, buildtree] -# Return true if a filter doesn't completely match a configuration. +# Return true if a filter completely matches a configuration. def check_filter(config_dict, filter_dict): for name, value in filter_dict.iteritems(): if not name in config_dict: - return True + return False if isinstance(value[1], str): if value[0] != (config_dict[name] == value[1]): - return True + return False else: if value[0] != bool(value[1].match(config_dict[name])): - return True + return False + + return True + +def check_filter_relevant(config_dict, filter_dict): + for name, value in filter_dict.iteritems(): + 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): + return True + + 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): + config_dict, filters_list = args + + if not check_filters_list_relevant(config_dict, filters_list): + return True + + for filter_dict in filters_list: + if check_filter(config_dict, filter_dict): + return True return False # Return true if a configuration passes all the given filters. -def check_filters(args): +def check_blocking_filters(args): config_dict, filters_list = args for filter_dict in filters_list: - if (not check_filter(config_dict, filter_dict)): + if check_filter(config_dict, filter_dict): return False return True -def filter_configs_list(configs_list, filters_list): - configs_and_filters = map(lambda x: (x, filters_list), configs_list) - return map(lambda x: x[0], filter(check_filters, configs_and_filters)) +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)) + return configs_list def find_options_dict(options_sets, name): if name not in options_sets: @@ -270,7 +321,8 @@ def main(): print 'set: ' + args.set configs_list = filter_configs_list(gen_configs_list(options_dict), - all_filters_list) + passing_filters_list, + blocking_filters_list) nr_configs = len(configs_list) print 'total: ' + str(nr_configs) |