Mercurial > lcfOS
annotate 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 |
rev | line source |
---|---|
329 | 1 |
2 """ | |
3 Defines task classes that can compile, link etc.. | |
4 Task can depend upon one another. | |
5 """ | |
6 | |
7 import logging | |
8 | |
9 from .c3 import Builder | |
10 from .irutils import Verifier | |
11 from .codegen import CodeGenerator | |
12 from .transform import CleanPass, RemoveAddZero | |
337 | 13 from .tasks import Task, TaskError |
14 from . import DiagnosticsManager, CompilerError | |
334 | 15 from .assembler import Assembler |
16 from .objectfile import ObjectFile | |
17 from .linker import Linker | |
348 | 18 from .outstream import BinaryOutputStream, MasterOutputStream, LoggerOutputStream |
366 | 19 from .target.target_list import targets |
20 from .target import Target | |
329 | 21 |
335 | 22 |
366 | 23 def fix_target(tg): |
24 """ Try to return an instance of the Target class """ | |
25 if isinstance(tg, Target): | |
26 return tg | |
27 elif isinstance(tg, str): | |
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 | |
34 | |
35 def fix_file(f): | |
36 """ Determine if argument is a file like object or make it so! """ | |
37 if hasattr(f, 'read'): | |
38 # Assume this is a file like object | |
39 return f | |
40 elif isinstance(f, str): | |
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 | |
331 | 51 class BuildTask(Task): |
334 | 52 """ Base task for all kind of weird build tasks """ |
331 | 53 def __init__(self, name): |
54 super().__init__(name) | |
55 self.logger = logging.getLogger('buildtask') | |
56 | |
57 | |
58 class Assemble(BuildTask): | |
334 | 59 """ Task that can runs the assembler over the source and enters the |
60 output into an object file """ | |
61 def __init__(self, source, target, output_object): | |
329 | 62 super().__init__('Assemble') |
366 | 63 self.source = fix_file(source) |
334 | 64 self.output = output_object |
366 | 65 o2 = BinaryOutputStream(self.output) |
66 o1 = LoggerOutputStream() | |
67 self.ostream = MasterOutputStream([o1, o2]) | |
68 self.assembler = Assembler(fix_target(target)) | |
329 | 69 |
70 def run(self): | |
366 | 71 self.logger.debug('Assembling into code section') |
348 | 72 self.ostream.select_section('code') |
346 | 73 self.assembler.assemble(self.source, self.ostream) |
366 | 74 self.logger.debug('Assembling finished') |
329 | 75 |
76 | |
331 | 77 class Compile(BuildTask): |
334 | 78 """ Task that compiles C3 source for some target into an object file """ |
329 | 79 def __init__(self, sources, includes, target, output_object): |
80 super().__init__('Compile') | |
366 | 81 self.sources = list(map(fix_file, sources)) |
82 self.includes = list(map(fix_file, includes)) | |
83 self.target = fix_target(target) | |
329 | 84 self.output = output_object |
85 | |
86 def run(self): | |
334 | 87 self.logger.debug('Compile started') |
329 | 88 diag = DiagnosticsManager() |
89 c3b = Builder(diag, self.target) | |
90 cg = CodeGenerator(self.target) | |
91 | |
92 for ircode in c3b.build(self.sources, self.includes): | |
93 if not ircode: | |
354 | 94 # Something went wrong, do not continue the code generation |
95 continue | |
329 | 96 |
97 d = {'ircode':ircode} | |
334 | 98 self.logger.debug('Verifying code {}'.format(ircode), extra=d) |
329 | 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} | |
334 | 111 self.logger.debug('Starting code generation for {}'.format(ircode), extra=d) |
348 | 112 |
113 o2 = BinaryOutputStream(self.output) | |
114 o1 = LoggerOutputStream() | |
366 | 115 o = MasterOutputStream([o1, o2]) |
334 | 116 cg.generate(ircode, o) |
329 | 117 |
118 if not c3b.ok: | |
119 diag.printErrors() | |
120 raise TaskError('Compile errors') | |
121 | |
122 | |
331 | 123 class Link(BuildTask): |
334 | 124 """ Link together a collection of object files """ |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
125 def __init__(self, objects, layout, output_file): |
329 | 126 super().__init__('Link') |
366 | 127 self.objects = list(map(fix_object, objects)) |
334 | 128 self.linker = Linker() |
129 self.duration = 0.1337 | |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
130 self.layout = layout |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
131 self.output_file = output_file |
334 | 132 |
133 def run(self): | |
337 | 134 try: |
135 output_obj = self.linker.link(self.objects, self.layout) | |
136 except CompilerError as e: | |
137 raise TaskError(e.msg) | |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
138 code = output_obj.get_section('code').data |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
139 with open(self.output_file, 'wb') as f: |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
140 f.write(code) |
329 | 141 |
142 | |
336
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
143 class ObjCopy(BuildTask): |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
144 def __init__(self, objects, output_file): |
d1ecc493384e
Added spiffy armtoken class for bit fiddeling. Added cool test that checks for build repeatability
Windel Bouwman
parents:
335
diff
changeset
|
145 super().__init__('ObjCopy') |
329 | 146 |