view python/zcc.py @ 331:a78b41ff6ad2

Added better recipe files
author Windel Bouwman
date Fri, 07 Feb 2014 12:39:59 +0100
parents 8f6f3ace4e78
children 87feb8a23b4d
line wrap: on
line source

#!/usr/bin/env python

import sys
import os
import argparse
import logging
import yaml

from ppci.buildtasks import Compile
from ppci.tasks import TaskRunner
from ppci.report import RstFormatter
import outstream
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='WARN')
    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:
    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.load_dict(recipe, runner)

    def relpath(self, filename):
        return os.path.join(self.recipe_dir, filename)

    def openfile(self, filename):
        return open(self.relpath(filename), 'r')

    def load_dict(self, recipe, runner):
        for command, value in recipe.items():
            if command == 'compile':
                sources = [self.openfile(s) for s in value['sources']]
                includes = [self.openfile(i) for i in value['includes']]
                target = targets[value['machine']]
                output = outstream.TextOutputStream()
                runner.add_task(Compile(sources, includes, target, output))
            elif command == 'link':
                self.load_dict(value['inputs'], runner)
                #runner.add_task(Link())
            elif command == 'assemble':
                pass
            elif command == 'apps':
                for a in value:
                    self.load_dict(a, runner)
            else:
                raise NotImplementedError(command)


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]
        outs = outstream.TextOutputStream()
        runner.add_task(Compile(args.source, args.imp, tg, outs))
    elif args.command == 'recipe':
        recipe_loader = RecipeLoader()
        recipe_loader.load_file(args.recipe_file, runner)
    else:
        raise NotImplementedError('Invalid option')

    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))