view python/ppci/buildtasks.py @ 377:9667d78ba79e

Switched to xml for project description
author Windel Bouwman
date Fri, 11 Apr 2014 15:47:50 +0200
parents 39bf68bf1891
children 6df89163e114
line wrap: on
line source


"""
Defines task classes that can compile, link etc..
Task can depend upon one another.
"""

import logging
import json

from .tasks import Task, TaskError, register_task
from .buildfunctions import c3compile, link, assemble
from pyyacc import ParserException
from . import CompilerError


@register_task("empty")
class EmptyTask(Task):
    """ Basic task that does nothing """
    def run(self):
        pass


@register_task("echo")
class EchoTask(Task):
    """ Simple task that echoes a message """
    def run(self):
        message = self.arguments['message']
        print(message)


@register_task("property")
class Property(Task):
    """ Sets a property to a value """
    def run(self):
        name = self.arguments['name']
        value = self.arguments['value']
        self.target.project.set_property(name, value)


@register_task("assemble")
class AssembleTask(Task):
    """ Task that can runs the assembler over the source and enters the 
        output into an object file """

    def run(self):
        target = self.get_argument('target')
        source = self.relpath(self.get_argument('source'))
        output_filename = self.relpath(self.get_argument('output'))

        try:
            output = assemble(source, target)
        except ParserException as e:
            raise TaskError('Error during assembly:' + str(e))
        except CompilerError as e:
            raise TaskError('Error during assembly:' + str(e))
        with open(output_filename, 'w') as f:
            output.save(f)
        self.logger.debug('Assembling finished')


@register_task("compile")
class C3cTask(Task):
    """ Task that compiles C3 source for some target into an object file """
    def run(self):
        target = self.get_argument('target')
        sources = self.open_file_set(self.arguments['sources'])
        output_filename = self.relpath(self.get_argument('output'))
        if 'includes' in self.arguments:
            includes = self.open_file_set(self.arguments['includes'])
        else:
            includes = []

        output = c3compile(sources, includes, target)
        # Store output:
        with open(output_filename, 'w') as f:
            output.save(f)


def make_num(txt):
    if txt.startswith('0x'):
        return int(txt[2:], 16)
    else:
        return int(txt)


def load_layout(filename):
    """ Load a linker layout file which contains directives where sections
        must be placed into memory. """
    try:
        with open(filename, 'r') as f:
            layout = json.load(f)
    except OSError as e:
        raise TaskError(str(e))
    for s in layout:
        layout[s] = make_num(layout[s])
    return layout


@register_task("link")
class LinkTask(Task):
    """ Link together a collection of object files """
    def run(self):
        layout = load_layout(self.relpath(self.get_argument('layout')))
        objects = self.open_file_set(self.get_argument('objects'))
        output_file = self.relpath(self.get_argument('output'))

        try:
            output_obj = link(objects, layout)
        except CompilerError as e:
            raise TaskError(e.msg)
        # TODO: use layout here:
        code = output_obj.get_section('code').data
        with open(output_file, 'wb') as f:
            f.write(code)


class ObjCopyTask(Task):
    def run(self):
        pass