Mercurial > lcfOS
comparison 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 |
comparison
equal
deleted
inserted
replaced
376:1e951e71d3f1 | 377:9667d78ba79e |
---|---|
3 Defines task classes that can compile, link etc.. | 3 Defines task classes that can compile, link etc.. |
4 Task can depend upon one another. | 4 Task can depend upon one another. |
5 """ | 5 """ |
6 | 6 |
7 import logging | 7 import logging |
8 import json | |
8 | 9 |
9 from .c3 import Builder | 10 from .tasks import Task, TaskError, register_task |
10 from .irutils import Verifier | 11 from .buildfunctions import c3compile, link, assemble |
11 from .codegen import CodeGenerator | 12 from pyyacc import ParserException |
12 from .transform import CleanPass, RemoveAddZero | 13 from . import CompilerError |
13 from .tasks import Task, TaskError | |
14 from . import DiagnosticsManager, CompilerError | |
15 from .assembler import Assembler | |
16 from .objectfile import ObjectFile | |
17 from .linker import Linker | |
18 from .outstream import BinaryOutputStream, MasterOutputStream, LoggerOutputStream | |
19 from .target.target_list import targets | |
20 from .target import Target | |
21 | 14 |
22 | 15 |
23 def fix_target(tg): | 16 @register_task("empty") |
24 """ Try to return an instance of the Target class """ | 17 class EmptyTask(Task): |
25 if isinstance(tg, Target): | 18 """ Basic task that does nothing """ |
26 return tg | 19 def run(self): |
27 elif isinstance(tg, str): | 20 pass |
28 if tg in targets: | |
29 return targets[tg] | |
30 else: | |
31 raise TaskError('Target {} not found'.format(tg)) | |
32 raise TaskError('Invalid target {}'.format(tg)) | |
33 | 21 |
34 | 22 |
35 def fix_file(f): | 23 @register_task("echo") |
36 """ Determine if argument is a file like object or make it so! """ | 24 class EchoTask(Task): |
37 if hasattr(f, 'read'): | 25 """ Simple task that echoes a message """ |
38 # Assume this is a file like object | 26 def run(self): |
39 return f | 27 message = self.arguments['message'] |
40 elif isinstance(f, str): | 28 print(message) |
41 return open(f, 'r') | |
42 else: | |
43 raise TaskError('cannot use {} as input'.format(f)) | |
44 | |
45 def fix_object(o): | |
46 if isinstance(o, ObjectFile): | |
47 return o | |
48 else: | |
49 raise TaskError('Cannot use {} as objectfile'.format(o)) | |
50 | |
51 class BuildTask(Task): | |
52 """ Base task for all kind of weird build tasks """ | |
53 def __init__(self, name): | |
54 super().__init__(name) | |
55 self.logger = logging.getLogger('buildtask') | |
56 | 29 |
57 | 30 |
58 class Assemble(BuildTask): | 31 @register_task("property") |
32 class Property(Task): | |
33 """ Sets a property to a value """ | |
34 def run(self): | |
35 name = self.arguments['name'] | |
36 value = self.arguments['value'] | |
37 self.target.project.set_property(name, value) | |
38 | |
39 | |
40 @register_task("assemble") | |
41 class AssembleTask(Task): | |
59 """ Task that can runs the assembler over the source and enters the | 42 """ Task that can runs the assembler over the source and enters the |
60 output into an object file """ | 43 output into an object file """ |
61 def __init__(self, source, target, output_object): | |
62 super().__init__('Assemble') | |
63 self.source = fix_file(source) | |
64 self.output = output_object | |
65 o2 = BinaryOutputStream(self.output) | |
66 o1 = LoggerOutputStream() | |
67 self.ostream = MasterOutputStream([o1, o2]) | |
68 self.assembler = Assembler(fix_target(target)) | |
69 | 44 |
70 def run(self): | 45 def run(self): |
71 self.logger.debug('Assembling into code section') | 46 target = self.get_argument('target') |
72 self.ostream.select_section('code') | 47 source = self.relpath(self.get_argument('source')) |
73 self.assembler.assemble(self.source, self.ostream) | 48 output_filename = self.relpath(self.get_argument('output')) |
49 | |
50 try: | |
51 output = assemble(source, target) | |
52 except ParserException as e: | |
53 raise TaskError('Error during assembly:' + str(e)) | |
54 except CompilerError as e: | |
55 raise TaskError('Error during assembly:' + str(e)) | |
56 with open(output_filename, 'w') as f: | |
57 output.save(f) | |
74 self.logger.debug('Assembling finished') | 58 self.logger.debug('Assembling finished') |
75 | 59 |
76 | 60 |
77 class Compile(BuildTask): | 61 @register_task("compile") |
62 class C3cTask(Task): | |
78 """ Task that compiles C3 source for some target into an object file """ | 63 """ Task that compiles C3 source for some target into an object file """ |
79 def __init__(self, sources, includes, target, output_object): | 64 def run(self): |
80 super().__init__('Compile') | 65 target = self.get_argument('target') |
81 self.sources = list(map(fix_file, sources)) | 66 sources = self.open_file_set(self.arguments['sources']) |
82 self.includes = list(map(fix_file, includes)) | 67 output_filename = self.relpath(self.get_argument('output')) |
83 self.target = fix_target(target) | 68 if 'includes' in self.arguments: |
84 self.output = output_object | 69 includes = self.open_file_set(self.arguments['includes']) |
70 else: | |
71 includes = [] | |
85 | 72 |
86 def run(self): | 73 output = c3compile(sources, includes, target) |
87 self.logger.debug('Compile started') | 74 # Store output: |
88 diag = DiagnosticsManager() | 75 with open(output_filename, 'w') as f: |
89 c3b = Builder(diag, self.target) | 76 output.save(f) |
90 cg = CodeGenerator(self.target) | |
91 | |
92 for ircode in c3b.build(self.sources, self.includes): | |
93 if not ircode: | |
94 # Something went wrong, do not continue the code generation | |
95 continue | |
96 | |
97 d = {'ircode':ircode} | |
98 self.logger.debug('Verifying code {}'.format(ircode), extra=d) | |
99 Verifier().verify(ircode) | |
100 | |
101 # Optimization passes: | |
102 CleanPass().run(ircode) | |
103 Verifier().verify(ircode) | |
104 RemoveAddZero().run(ircode) | |
105 Verifier().verify(ircode) | |
106 CleanPass().run(ircode) | |
107 Verifier().verify(ircode) | |
108 | |
109 # Code generation: | |
110 d = {'ircode':ircode} | |
111 self.logger.debug('Starting code generation for {}'.format(ircode), extra=d) | |
112 | |
113 o2 = BinaryOutputStream(self.output) | |
114 o1 = LoggerOutputStream() | |
115 o = MasterOutputStream([o1, o2]) | |
116 cg.generate(ircode, o) | |
117 | |
118 if not c3b.ok: | |
119 diag.printErrors() | |
120 raise TaskError('Compile errors') | |
121 | 77 |
122 | 78 |
123 class Link(BuildTask): | 79 def make_num(txt): |
80 if txt.startswith('0x'): | |
81 return int(txt[2:], 16) | |
82 else: | |
83 return int(txt) | |
84 | |
85 | |
86 def load_layout(filename): | |
87 """ Load a linker layout file which contains directives where sections | |
88 must be placed into memory. """ | |
89 try: | |
90 with open(filename, 'r') as f: | |
91 layout = json.load(f) | |
92 except OSError as e: | |
93 raise TaskError(str(e)) | |
94 for s in layout: | |
95 layout[s] = make_num(layout[s]) | |
96 return layout | |
97 | |
98 | |
99 @register_task("link") | |
100 class LinkTask(Task): | |
124 """ Link together a collection of object files """ | 101 """ Link together a collection of object files """ |
125 def __init__(self, objects, layout, output_file): | 102 def run(self): |
126 super().__init__('Link') | 103 layout = load_layout(self.relpath(self.get_argument('layout'))) |
127 self.objects = list(map(fix_object, objects)) | 104 objects = self.open_file_set(self.get_argument('objects')) |
128 self.linker = Linker() | 105 output_file = self.relpath(self.get_argument('output')) |
129 self.duration = 0.1337 | |
130 self.layout = layout | |
131 self.output_file = output_file | |
132 | 106 |
133 def run(self): | |
134 try: | 107 try: |
135 output_obj = self.linker.link(self.objects, self.layout) | 108 output_obj = link(objects, layout) |
136 except CompilerError as e: | 109 except CompilerError as e: |
137 raise TaskError(e.msg) | 110 raise TaskError(e.msg) |
111 # TODO: use layout here: | |
138 code = output_obj.get_section('code').data | 112 code = output_obj.get_section('code').data |
139 with open(self.output_file, 'wb') as f: | 113 with open(output_file, 'wb') as f: |
140 f.write(code) | 114 f.write(code) |
141 | 115 |
142 | 116 |
143 class ObjCopy(BuildTask): | 117 class ObjCopyTask(Task): |
144 def __init__(self, objects, output_file): | 118 def run(self): |
145 super().__init__('ObjCopy') | 119 pass |
146 | 120 |