Mercurial > lcfOS
view python/zcc.py @ 336:d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
author | Windel Bouwman |
---|---|
date | Wed, 19 Feb 2014 22:32:15 +0100 |
parents | 6f4753202b9a |
children | 86b02c98a717 |
line wrap: on
line source
#!/usr/bin/env python import sys import os import argparse import logging import yaml from ppci.buildtasks import Compile, Assemble, Link from ppci.tasks import TaskRunner from ppci.report import RstFormatter from ppci.objectfile import ObjectFile from target.target_list import target_list import ppci def logLevel(s): """ Converts a string to a valid logging level """ numeric_level = getattr(logging, s.upper(), None) if not isinstance(numeric_level, int): raise ValueError('Invalid log level: {}'.format(s)) return numeric_level targets = {t.name: t for t in target_list} targetnames = list(targets.keys()) def make_parser(): parser = argparse.ArgumentParser(description='lcfos Compiler') parser.add_argument('--log', help='Log level (INFO,DEBUG,[WARN])', type=logLevel, default='INFO') parser.add_argument('--display-build-steps', action='store_true') sub_parsers = parser.add_subparsers(title='commands', description='possible commands', dest='command') recipe_parser = sub_parsers.add_parser('recipe', help="Bake recipe") recipe_parser.add_argument('recipe_file', help='recipe file') compile_parser = sub_parsers.add_parser('compile', help="compile source") compile_parser.add_argument('source', type=argparse.FileType('r'), help='the source file to build', nargs="+") compile_parser.add_argument('-i', '--imp', type=argparse.FileType('r'), help='Possible import module', action='append', default=[]) compile_parser.add_argument('--target', help="Backend selection", choices=targetnames, required=True) compile_parser.add_argument('-o', '--output', help='Output file', metavar='filename') compile_parser.add_argument('--report', help='Specify a file to write the compile report to', type=argparse.FileType('w')) return parser class RecipeLoader: """ Loads a recipe into a runner from a dictionary or file """ def __init__(self): self.directive_handlers = {} for a in dir(self): if a.startswith('handle_'): f = getattr(self, a) self.directive_handlers[a[7:]] = f def load_file(self, recipe_file, runner): """ Loads a recipe dictionary into a task runner """ self.recipe_dir = os.path.abspath(os.path.dirname(recipe_file)) with open(recipe_file, 'r') as f: recipe = yaml.load(f) self.runner = runner self.load_dict(recipe) def relpath(self, filename): return os.path.join(self.recipe_dir, filename) def openfile(self, filename): return open(self.relpath(filename), 'r') def handle_compile(self, value): sources = [self.openfile(s) for s in value['sources']] includes = [self.openfile(i) for i in value['includes']] target = targets[value['machine']] output = ObjectFile() task = Compile(sources, includes, target, output) self.runner.add_task(task) return task def handle_assemble(self, value): asm_src = self.openfile(value['source']) target = targets[value['machine']] output = ObjectFile() task = Assemble(asm_src, target, output) self.runner.add_task(task) return task def handle_link(self, value): inputs = value['inputs'] objs = [] for i in inputs: task = self.load_dict(i) objs.append(task.output) layout = value['layout'] output = self.relpath(value['output']) self.runner.add_task(Link(objs, layout, output)) def handle_apps(self, value): for a in value: self.load_dict(a) def load_dict(self, recipe): for command, value in recipe.items(): return self.directive_handlers[command](value) def main(args): # Configure some logging: logging.getLogger().setLevel(logging.DEBUG) ch = logging.StreamHandler() ch.setFormatter(logging.Formatter(ppci.logformat)) ch.setLevel(args.log) logging.getLogger().addHandler(ch) runner = TaskRunner() if args.command == 'compile': tg = targets[args.target] output = ObjectFile() runner.add_task(Compile(args.source, args.imp, tg, output)) elif args.command == 'recipe': recipe_loader = RecipeLoader() recipe_loader.load_file(args.recipe_file, runner) else: raise NotImplementedError('Invalid option') if args.display_build_steps: runner.display() res = 0 else: res = runner.run_tasks() logging.getLogger().removeHandler(ch) return res if __name__ == '__main__': parser = make_parser() arguments = parser.parse_args() if not arguments.command: parser.print_usage() sys.exit(1) sys.exit(main(arguments))