From 1d22f2a89891445ac6e3353bff20ff3701685424 Mon Sep 17 00:00:00 2001 From: Nicolas Schodet Date: Sat, 8 Dec 2012 23:24:41 +0100 Subject: digital/ucoolib/build: add target specific configuration --- digital/ucoolib/build/config.mk | 3 +- digital/ucoolib/build/tools/config-gen | 85 +++++++++++++++++++--- .../ucoolib/build/tools/test/Config-nok-badtarget | 5 ++ .../build/tools/test/Config-nok-missdefault | 2 + .../ucoolib/build/tools/test/Config-nok-nodefault | 2 + .../ucoolib/build/tools/test/Config-nok-toomany | 8 ++ .../ucoolib/build/tools/test/Config-nok-unknown | 2 + digital/ucoolib/build/tools/test/Config-ok | 5 ++ digital/ucoolib/build/tools/test/Makefile | 16 ++++ digital/ucoolib/build/tools/test/a-Config | 3 + digital/ucoolib/build/tools/test/b-Config | 2 + digital/ucoolib/build/top.mk | 3 + 12 files changed, 124 insertions(+), 12 deletions(-) create mode 100644 digital/ucoolib/build/tools/test/Config-nok-badtarget create mode 100644 digital/ucoolib/build/tools/test/Config-nok-missdefault create mode 100644 digital/ucoolib/build/tools/test/Config-nok-nodefault create mode 100644 digital/ucoolib/build/tools/test/Config-nok-toomany create mode 100644 digital/ucoolib/build/tools/test/Config-nok-unknown create mode 100644 digital/ucoolib/build/tools/test/Config-ok create mode 100644 digital/ucoolib/build/tools/test/Makefile create mode 100644 digital/ucoolib/build/tools/test/a-Config create mode 100644 digital/ucoolib/build/tools/test/b-Config (limited to 'digital/ucoolib/build') diff --git a/digital/ucoolib/build/config.mk b/digital/ucoolib/build/config.mk index cdffc16e..ff3fa568 100644 --- a/digital/ucoolib/build/config.mk +++ b/digital/ucoolib/build/config.mk @@ -28,7 +28,8 @@ clean: config-clean $(OBJDIR)/config.list: $(CONFIG_LIST) $(CONFIG_FORCE) | $(OBJDIR) @echo "CONF $(PROJECT_CONFIG)" $Q$(BASE)/build/tools/config-gen -H $(OBJDIR)/config/%.hh \ - -p $(PROJECT_CONFIG) $(MODULES_CONFIG) + -p $(PROJECT_CONFIG) -T '$(TARGETS_SUBTARGETS)' \ + $(MODULES_CONFIG) $Qecho "CONFIG_LIST_OLD = $(CONFIG_LIST)" > $@ config-clean: diff --git a/digital/ucoolib/build/tools/config-gen b/digital/ucoolib/build/tools/config-gen index 3feffbe8..9bc578bc 100755 --- a/digital/ucoolib/build/tools/config-gen +++ b/digital/ucoolib/build/tools/config-gen @@ -2,6 +2,7 @@ """Read build configuration and generate header files.""" import optparse import ConfigParser +import collections import sys import re import os @@ -21,7 +22,7 @@ def read_config(modules_configs, project_config): parser.readfp(mcf) # Save the list of existing items for later check. def config_items(parser): - return set('%s:%s' % (section, item) + return set('%s:%s' % (section.split(':')[0], item) for section in parser.sections() for item in parser.options(section)) modules_items = config_items(parser) @@ -40,24 +41,81 @@ def read_config(modules_configs, project_config): if unknown_items: raise RuntimeError("unknown configuration item: " + " ".join(unknown_items)) - # Check for items with no default value. - for section in parser.sections(): - for key, value in parser.items(section): - if value == '': + # OK, convert to more natural structure. + config = collections.defaultdict (lambda: collections.defaultdict(dict)) + for section in parser.sections(): + items = parser.items(section) + if ':' in section: + section, target = section.split(':', 1) + else: + target = None + for k, v in items: + config[section][k][target] = v + return config + +def check_config(config, targets, subtargets): + """Run consistency checks on configuration.""" + for section, section_dict in config.iteritems(): + for key, values in section_dict.iteritems(): + # Check targets. + for ts in values: + if ts is not None and ts not in subtargets: + raise RuntimeError("unknown target %s" % ts) + values_targets = reduce(lambda a, b: a + b, (subtargets[ts] + for ts in values if ts is not None), [ ]) + values_targets_set = set(values_targets) + # Check for items with no default value. + if values[None] == '': + if not values_targets: raise RuntimeError("no value given for %s:%s" % (section, key)) - # OK, convert to more natural structure. - return dict((section, parser.items(section)) - for section in parser.sections()) + else: + if values_targets_set < targets: + raise RuntimeError("no value given for %s:%s for" + " targets: %s" % (section, key, + ', '.join (targets - values_targets_set))) + # Check for items overridden several times for the same target. + if len(values_targets) != len(values_targets_set): + raise RuntimeError("several values given for %s:%s for the" + " same target" % (section, key)) + +def parse_targets(targets_option): + """Parse a space separated target:subtarget list. Return a set of + targets, and a mapping of each subtarget to a list of target.""" + if targets_option is None: + targets_option = '' + targets = set() + subtargets = collections.defaultdict(list) + for tpair in targets_option.split(): + tpairl = tpair.split(':') + if len(tpairl) != 2: + raise RuntimeError("bad target:subtarget pair %s" % tpair) + target, subtarget = tpairl + targets.add(target) + subtargets[subtarget].append(target) + return targets, dict(subtargets) def write_header(filename, section, section_dict): """Write (update) a section to a C header file.""" # Prepare new content. items = [ ] section = section.replace('/', '_').upper() - for key, value in section_dict: - items.append('#define UCOO_CONFIG_%s_%s (%s)' - % (section, key.upper(), value)) + for key, values in section_dict.iteritems(): + cond = False + for target, value in values.iteritems(): + if target is None: continue + item_fmt = ('#ifdef TARGET_{target}\n' + '# define UCOO_CONFIG_{section}_{key} ({value})\n' + '#endif') + items.append(item_fmt.format(section=section, key=key.upper(), + target=target, value=value)) + cond = True + item_fmt = '#define UCOO_CONFIG_{section}_{key} ({value})' + if cond: + item_fmt = '#ifndef UCOO_CONFIG_{section}_{key}\n# ' \ + + item_fmt[1:] + '\n#endif' + items.append(item_fmt.format(section=section, key=key.upper(), + value=values[None])) guard = re.sub(r'\W', '_', filename) content = '\n'.join([ '#ifndef %s' % guard, @@ -99,10 +157,15 @@ if __name__ == '__main__': parser.add_option('-H', '--c-header-template', metavar='TEMPLATE', help="name template for C header files" + " (use % as section placeholder)") + parser.add_option('-T', '--targets', metavar='"LIST"', + help="space separated list of target:subtarget pairs (used for" + + " error checking)") options, modules_configs = parser.parse_args() try: + targets, subtargets = parse_targets(options.targets) config = read_config(modules_configs, options.project_config) + check_config(config, targets, subtargets) if options.c_header_template: write_headers(options.c_header_template, config) except RuntimeError, e: diff --git a/digital/ucoolib/build/tools/test/Config-nok-badtarget b/digital/ucoolib/build/tools/test/Config-nok-badtarget new file mode 100644 index 00000000..d3aef600 --- /dev/null +++ b/digital/ucoolib/build/tools/test/Config-nok-badtarget @@ -0,0 +1,5 @@ +[a] +bar = 2 + +[a:plop] +bar = 3 diff --git a/digital/ucoolib/build/tools/test/Config-nok-missdefault b/digital/ucoolib/build/tools/test/Config-nok-missdefault new file mode 100644 index 00000000..fb2bc0bf --- /dev/null +++ b/digital/ucoolib/build/tools/test/Config-nok-missdefault @@ -0,0 +1,2 @@ +[a:host] +bar = 2 diff --git a/digital/ucoolib/build/tools/test/Config-nok-nodefault b/digital/ucoolib/build/tools/test/Config-nok-nodefault new file mode 100644 index 00000000..384ce663 --- /dev/null +++ b/digital/ucoolib/build/tools/test/Config-nok-nodefault @@ -0,0 +1,2 @@ +[a] +foo = 2 diff --git a/digital/ucoolib/build/tools/test/Config-nok-toomany b/digital/ucoolib/build/tools/test/Config-nok-toomany new file mode 100644 index 00000000..13549e94 --- /dev/null +++ b/digital/ucoolib/build/tools/test/Config-nok-toomany @@ -0,0 +1,8 @@ +[a] +bar = 2 + +[a:stm32f4] +bar = 3 + +[a:arm] +bar = 4 diff --git a/digital/ucoolib/build/tools/test/Config-nok-unknown b/digital/ucoolib/build/tools/test/Config-nok-unknown new file mode 100644 index 00000000..7df223d7 --- /dev/null +++ b/digital/ucoolib/build/tools/test/Config-nok-unknown @@ -0,0 +1,2 @@ +[a] +bazar = 2 diff --git a/digital/ucoolib/build/tools/test/Config-ok b/digital/ucoolib/build/tools/test/Config-ok new file mode 100644 index 00000000..19b46141 --- /dev/null +++ b/digital/ucoolib/build/tools/test/Config-ok @@ -0,0 +1,5 @@ +[a] +bar = 2 + +[a:host] +bar = 3 diff --git a/digital/ucoolib/build/tools/test/Makefile b/digital/ucoolib/build/tools/test/Makefile new file mode 100644 index 00000000..59bd2da0 --- /dev/null +++ b/digital/ucoolib/build/tools/test/Makefile @@ -0,0 +1,16 @@ +CONFIG_GEN = ../config-gen +MODULES_CONFIG = a-Config b-Config + +TARGETS := host:host stm32f4:stm32f4 stm32f4:arm + +TESTS = ok nok-unknown nok-nodefault nok-missdefault nok-toomany nok-badtarget + +all: $(TESTS:%=test-%) + +test-%: Config-% $(MODULES_CONFIG) $(CONFIG_GEN) + expect=$(if $(filter ok,$*),0,1); \ + $(CONFIG_GEN) -p $< -H out-$*/%.hh -T "$(TARGETS)" $(MODULES_CONFIG); \ + test $$expect -eq $$? + +clean: + rm -rf $(TESTS:%=out-%) diff --git a/digital/ucoolib/build/tools/test/a-Config b/digital/ucoolib/build/tools/test/a-Config new file mode 100644 index 00000000..ed66ccc4 --- /dev/null +++ b/digital/ucoolib/build/tools/test/a-Config @@ -0,0 +1,3 @@ +[a] +foo = 1 +bar = diff --git a/digital/ucoolib/build/tools/test/b-Config b/digital/ucoolib/build/tools/test/b-Config new file mode 100644 index 00000000..b0bb7535 --- /dev/null +++ b/digital/ucoolib/build/tools/test/b-Config @@ -0,0 +1,2 @@ +[b] +foobar = "hello" diff --git a/digital/ucoolib/build/top.mk b/digital/ucoolib/build/top.mk index a944b2c7..71fe1be0 100644 --- a/digital/ucoolib/build/top.mk +++ b/digital/ucoolib/build/top.mk @@ -63,3 +63,6 @@ define TARGETS_template include $$(BASE)/build/$1.mk endef $(foreach target,$(TARGETS),$(eval $(call TARGETS_template,$(target)))) + +TARGETS_SUBTARGETS := $(foreach target,$(TARGETS),$(target):$(target) \ + $(foreach subtarget,$($(target)_SUBTARGETS),$(target):$(subtarget))) -- cgit v1.2.3