From beaa75f184d07855ea40da2b1e336cf1fe86a7b8 Mon Sep 17 00:00:00 2001 From: Nicolas Schodet Date: Sat, 20 Oct 2012 09:56:17 +0200 Subject: digital/ucoolib: add build time configuration system --- digital/ucoolib/build/config.mk | 32 ++++++++++ digital/ucoolib/build/tools/config-gen | 113 +++++++++++++++++++++++++++++++++ digital/ucoolib/build/top.mk | 4 ++ 3 files changed, 149 insertions(+) create mode 100644 digital/ucoolib/build/config.mk create mode 100755 digital/ucoolib/build/tools/config-gen (limited to 'digital/ucoolib/build') diff --git a/digital/ucoolib/build/config.mk b/digital/ucoolib/build/config.mk new file mode 100644 index 00000000..6f3f527b --- /dev/null +++ b/digital/ucoolib/build/config.mk @@ -0,0 +1,32 @@ +# ucoolib - Microcontroller object oriented library. +# +# Build time configuration system. + +PROJECT_CONFIG ?= Config +MODULES_CONFIG := $(wildcard $(ALL_MODULES:%=$(BASE)/ucoolib/%/Config)) + +CONFIG_LIST := $(wildcard $(PROJECT_CONFIG)) $(MODULES_CONFIG) + +# Ensure that configuration is up to date, using two mechanisms: +# - make will make sure config.list is up to date as it is included. +# - comparison with CONFIG_LIST ensures that the list of included +# configuration (including the project configuration) is the same. +ifneq ($(MAKECMDGOALS),clean) +-include $(OBJDIR)/config.list +ifneq ($(CONFIG_LIST),$(CONFIG_LIST_OLD)) +CONFIG_FORCE := CONFIG_FORCE +endif +endif + +clean: config-clean + +.PHONY: config-clean CONFIG_FORCE + +$(OBJDIR)/config.list: $(CONFIG_LIST) $(CONFIG_FORCE) + @echo "CONF $(PROJECT_CONFIG)" + $Q$(BASE)/build/tools/config-gen -H $(OBJDIR)/config/%.hh \ + -p $(PROJECT_CONFIG) $(MODULES_CONFIG) + $Qecho "CONFIG_LIST_OLD = $(CONFIG_LIST)" > $@ + +config-clean: + rm -rf $(OBJDIR)/config $(OBJDIR)/config.list diff --git a/digital/ucoolib/build/tools/config-gen b/digital/ucoolib/build/tools/config-gen new file mode 100755 index 00000000..3feffbe8 --- /dev/null +++ b/digital/ucoolib/build/tools/config-gen @@ -0,0 +1,113 @@ +#!/usr/bin/python +"""Read build configuration and generate header files.""" +import optparse +import ConfigParser +import sys +import re +import os + +def read_config(modules_configs, project_config): + """Read configuration definitions and default values from module + configuration files, then merge project configuration.""" + parser = ConfigParser.SafeConfigParser() + # Read definitions and default values. + for mc in modules_configs: + try: + mcf = open(mc) + except IOError: + pass + else: + with mcf: + parser.readfp(mcf) + # Save the list of existing items for later check. + def config_items(parser): + return set('%s:%s' % (section, item) + for section in parser.sections() + for item in parser.options(section)) + modules_items = config_items(parser) + # Now read project configuration. + if project_config is not None: + try: + pcf = open(project_config) + except IOError: + pass + else: + with pcf: + parser.readfp(pcf) + # Check for unknown items. + project_items = config_items(parser) + unknown_items = project_items - modules_items + 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 == '': + 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()) + +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)) + guard = re.sub(r'\W', '_', filename) + content = '\n'.join([ + '#ifndef %s' % guard, + '#define %s' % guard, + '// Generated from configuration.', + ] + items + [ + '#endif', + '' ]) + # Check old content. + old_content = '' + try: + hf = open(filename) + except IOError: + pass + else: + with hf: + old_content = hf.read() + if old_content == content: + return + # Create output directory if needed. + dirname = os.path.dirname(filename) + if not os.path.exists(dirname): + os.makedirs(dirname) + # Write new content. + with open(filename, 'w') as hf: + hf.write(content) + +def write_headers(filename_pattern, config): + """Write (update) all sections to C header files.""" + for section, section_dict in config.iteritems(): + filename = filename_pattern.replace('%', section) + write_header(filename, section, section_dict) + +if __name__ == '__main__': + parser = optparse.OptionParser( + usage='%prog [options] modules configuration files...') + parser.add_option('-p', '--project-config', metavar='FILE', + help="project configuration file") + parser.add_option('-H', '--c-header-template', metavar='TEMPLATE', + help="name template for C header files" + + " (use % as section placeholder)") + options, modules_configs = parser.parse_args() + + try: + config = read_config(modules_configs, options.project_config) + if options.c_header_template: + write_headers(options.c_header_template, config) + except RuntimeError, e: + print >> sys.stderr, e + sys.exit(1) + except EnvironmentError, e: + print >> sys.stderr, e + sys.exit(1) diff --git a/digital/ucoolib/build/top.mk b/digital/ucoolib/build/top.mk index 29e8003f..adb4e950 100644 --- a/digital/ucoolib/build/top.mk +++ b/digital/ucoolib/build/top.mk @@ -44,6 +44,10 @@ vpath %.cc $(ALL_MODULES:%=$(BASE)/ucoolib/%) vpath %.c $(ALL_MODULES:%=$(BASE)/ucoolib/%) vpath %.S $(ALL_MODULES:%=$(BASE)/ucoolib/%) +# Configuration. + +include $(BASE)/build/config.mk + # Objects directory. $(OBJDIR): -- cgit v1.2.3