diff 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 diff
--- a/python/ppci/buildtasks.py	Tue Mar 25 19:36:51 2014 +0100
+++ b/python/ppci/buildtasks.py	Fri Apr 11 15:47:50 2014 +0200
@@ -5,142 +5,116 @@
 """
 
 import logging
+import json
 
-from .c3 import Builder
-from .irutils import Verifier
-from .codegen import CodeGenerator
-from .transform import CleanPass, RemoveAddZero
-from .tasks import Task, TaskError
-from . import DiagnosticsManager, CompilerError
-from .assembler import Assembler
-from .objectfile import ObjectFile
-from .linker import Linker
-from .outstream import BinaryOutputStream, MasterOutputStream, LoggerOutputStream
-from .target.target_list import targets
-from .target import Target
+from .tasks import Task, TaskError, register_task
+from .buildfunctions import c3compile, link, assemble
+from pyyacc import ParserException
+from . import CompilerError
 
 
-def fix_target(tg):
-    """ Try to return an instance of the Target class """
-    if isinstance(tg, Target):
-        return tg
-    elif isinstance(tg, str):
-        if tg in targets:
-            return targets[tg]
-        else:
-            raise TaskError('Target {} not found'.format(tg))
-    raise TaskError('Invalid target {}'.format(tg))
+@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)
 
 
-def fix_file(f):
-    """ Determine if argument is a file like object or make it so! """
-    if hasattr(f, 'read'):
-        # Assume this is a file like object
-        return f
-    elif isinstance(f, str):
-        return open(f, 'r')
-    else:
-        raise TaskError('cannot use {} as input'.format(f))
-
-def fix_object(o):
-    if isinstance(o, ObjectFile):
-        return o
-    else:
-        raise TaskError('Cannot use {} as objectfile'.format(o))
-
-class BuildTask(Task):
-    """ Base task for all kind of weird build tasks """
-    def __init__(self, name):
-        super().__init__(name)
-        self.logger = logging.getLogger('buildtask')
+@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)
 
 
-class Assemble(BuildTask):
+@register_task("assemble")
+class AssembleTask(Task):
     """ Task that can runs the assembler over the source and enters the 
         output into an object file """
-    def __init__(self, source, target, output_object):
-        super().__init__('Assemble')
-        self.source = fix_file(source)
-        self.output = output_object
-        o2 = BinaryOutputStream(self.output)
-        o1 = LoggerOutputStream()
-        self.ostream = MasterOutputStream([o1, o2])
-        self.assembler = Assembler(fix_target(target))
 
     def run(self):
-        self.logger.debug('Assembling into code section')
-        self.ostream.select_section('code')
-        self.assembler.assemble(self.source, self.ostream)
+        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')
 
 
-class Compile(BuildTask):
+@register_task("compile")
+class C3cTask(Task):
     """ Task that compiles C3 source for some target into an object file """
-    def __init__(self, sources, includes, target, output_object):
-        super().__init__('Compile')
-        self.sources = list(map(fix_file, sources))
-        self.includes = list(map(fix_file, includes))
-        self.target = fix_target(target)
-        self.output = output_object
-
     def run(self):
-        self.logger.debug('Compile started')
-        diag = DiagnosticsManager()
-        c3b = Builder(diag, self.target)
-        cg = CodeGenerator(self.target)
-
-        for ircode in c3b.build(self.sources, self.includes):
-            if not ircode:
-                # Something went wrong, do not continue the code generation
-                continue
+        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 = []
 
-            d = {'ircode':ircode}
-            self.logger.debug('Verifying code {}'.format(ircode), extra=d)
-            Verifier().verify(ircode)
+        output = c3compile(sources, includes, target)
+        # Store output:
+        with open(output_filename, 'w') as f:
+            output.save(f)
 
-            # Optimization passes:
-            CleanPass().run(ircode)
-            Verifier().verify(ircode)
-            RemoveAddZero().run(ircode)
-            Verifier().verify(ircode)
-            CleanPass().run(ircode)
-            Verifier().verify(ircode)
 
-            # Code generation:
-            d = {'ircode':ircode}
-            self.logger.debug('Starting code generation for {}'.format(ircode), extra=d)
-
-            o2 = BinaryOutputStream(self.output)
-            o1 = LoggerOutputStream()
-            o = MasterOutputStream([o1, o2])
-            cg.generate(ircode, o)
-
-        if not c3b.ok:
-            diag.printErrors()
-            raise TaskError('Compile errors')
+def make_num(txt):
+    if txt.startswith('0x'):
+        return int(txt[2:], 16)
+    else:
+        return int(txt)
 
 
-class Link(BuildTask):
+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 __init__(self, objects, layout, output_file):
-        super().__init__('Link')
-        self.objects = list(map(fix_object, objects))
-        self.linker = Linker()
-        self.duration = 0.1337
-        self.layout = layout
-        self.output_file = output_file
+    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'))
 
-    def run(self):
         try:
-            output_obj = self.linker.link(self.objects, self.layout)
+            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(self.output_file, 'wb') as f:
+        with open(output_file, 'wb') as f:
             f.write(code)
 
 
-class ObjCopy(BuildTask):
-    def __init__(self, objects, output_file):
-        super().__init__('ObjCopy')
+class ObjCopyTask(Task):
+    def run(self):
+        pass