Mercurial > lcfOS
view python/ppci/buildtasks.py @ 366:39bf68bf1891
Fix sample tests and deterministic build
author | Windel Bouwman |
---|---|
date | Fri, 21 Mar 2014 09:43:01 +0100 |
parents | 5477e499b039 |
children | 9667d78ba79e |
line wrap: on
line source
""" Defines task classes that can compile, link etc.. Task can depend upon one another. """ import logging 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 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)) 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') class Assemble(BuildTask): """ 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) self.logger.debug('Assembling finished') class Compile(BuildTask): """ 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 d = {'ircode':ircode} self.logger.debug('Verifying code {}'.format(ircode), extra=d) Verifier().verify(ircode) # 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') class Link(BuildTask): """ 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): try: output_obj = self.linker.link(self.objects, self.layout) except CompilerError as e: raise TaskError(e.msg) code = output_obj.get_section('code').data with open(self.output_file, 'wb') as f: f.write(code) class ObjCopy(BuildTask): def __init__(self, objects, output_file): super().__init__('ObjCopy')