377
|
1
|
|
2 """
|
|
3 This module contains a set of handy functions to invoke compilation,
|
|
4 linking
|
|
5 and assembling.
|
|
6 """
|
|
7
|
|
8 import logging
|
|
9 from .target import Target
|
|
10 from .c3 import Builder
|
|
11 from .irutils import Verifier
|
|
12 from .codegen import CodeGenerator
|
|
13 from .transform import CleanPass, RemoveAddZero
|
|
14 from .linker import Linker
|
383
|
15 from .layout import Layout, load_layout
|
377
|
16 from .target.target_list import targets
|
394
|
17 from .outstream import BinaryOutputStream
|
377
|
18 from .objectfile import ObjectFile, load_object
|
393
|
19 from . import DiagnosticsManager
|
|
20 from .tasks import TaskError, TaskRunner
|
|
21 from .recipe import RecipeLoader
|
381
|
22
|
385
|
23
|
377
|
24 def fix_target(tg):
|
|
25 """ Try to return an instance of the Target class """
|
|
26 if isinstance(tg, Target):
|
|
27 return tg
|
|
28 elif isinstance(tg, str):
|
|
29 if tg in targets:
|
|
30 return targets[tg]
|
|
31 raise TaskError('Invalid target {}'.format(tg))
|
|
32
|
381
|
33
|
377
|
34 def fix_file(f):
|
|
35 """ Determine if argument is a file like object or make it so! """
|
|
36 if hasattr(f, 'read'):
|
|
37 # Assume this is a file like object
|
|
38 return f
|
|
39 elif isinstance(f, str):
|
|
40 return open(f, 'r')
|
|
41 else:
|
|
42 raise TaskError('cannot use {} as input'.format(f))
|
|
43
|
381
|
44
|
377
|
45 def fix_object(o):
|
|
46 if isinstance(o, ObjectFile):
|
|
47 return o
|
|
48 elif isinstance(o, str):
|
|
49 with open(o, 'r') as f:
|
|
50 return load_object(f)
|
|
51 else:
|
|
52 raise TaskError('Cannot use {} as objectfile'.format(o))
|
|
53
|
|
54
|
383
|
55 def fix_layout(l):
|
|
56 if isinstance(l, Layout):
|
|
57 return l
|
|
58 elif hasattr(l, 'read'):
|
|
59 # Assume file handle
|
|
60 return load_layout(l)
|
|
61 elif isinstance(l, str):
|
|
62 with open(l, 'r') as f:
|
|
63 return load_layout(f)
|
|
64 else:
|
|
65 raise TaskError('Cannot use {} as layout'.format(l))
|
|
66
|
|
67
|
393
|
68 def construct(buildfile, targets=[]):
|
|
69 recipe_loader = RecipeLoader()
|
|
70 try:
|
|
71 project = recipe_loader.load_file(buildfile)
|
|
72 except OSError:
|
|
73 raise TaskError('Could not construct {}'.format(buildfile))
|
|
74 project = None
|
|
75
|
|
76 if project:
|
|
77 runner = TaskRunner()
|
|
78 res = runner.run(project, targets)
|
|
79 else:
|
|
80 res = 1
|
|
81
|
|
82 return res
|
|
83
|
|
84
|
377
|
85 def assemble(source, target):
|
381
|
86 """ Invoke the assembler on the given source, returns an object containing
|
|
87 the output. """
|
377
|
88 logger = logging.getLogger('assemble')
|
|
89 target = fix_target(target)
|
|
90 source = fix_file(source)
|
|
91 output = ObjectFile()
|
381
|
92 assembler = target.assembler
|
377
|
93 logger.debug('Assembling into code section')
|
394
|
94 ostream = BinaryOutputStream(output)
|
377
|
95 ostream.select_section('code')
|
386
|
96 assembler.prepare()
|
377
|
97 assembler.assemble(source, ostream)
|
381
|
98 assembler.flush()
|
377
|
99 return output
|
|
100
|
|
101
|
|
102 def c3compile(sources, includes, target):
|
381
|
103 """ Compile a set of sources for the given target """
|
377
|
104 logger = logging.getLogger('c3c')
|
|
105 logger.debug('C3 compilation started')
|
|
106 target = fix_target(target)
|
|
107 sources = [fix_file(fn) for fn in sources]
|
|
108 includes = [fix_file(fn) for fn in includes]
|
|
109 output = ObjectFile()
|
|
110 diag = DiagnosticsManager()
|
|
111 c3b = Builder(diag, target)
|
|
112 cg = CodeGenerator(target)
|
|
113
|
394
|
114 output_stream = BinaryOutputStream(output)
|
377
|
115
|
|
116 for ircode in c3b.build(sources, includes):
|
|
117 if not ircode:
|
|
118 # Something went wrong, do not continue the code generation
|
|
119 continue
|
|
120
|
393
|
121 d = {'ircode': ircode}
|
377
|
122 logger.debug('Verifying code {}'.format(ircode), extra=d)
|
|
123 Verifier().verify(ircode)
|
|
124
|
|
125 # Optimization passes:
|
|
126 CleanPass().run(ircode)
|
|
127 Verifier().verify(ircode)
|
|
128 RemoveAddZero().run(ircode)
|
|
129 Verifier().verify(ircode)
|
|
130 CleanPass().run(ircode)
|
|
131 Verifier().verify(ircode)
|
|
132
|
|
133 # Code generation:
|
393
|
134 d = {'ircode': ircode}
|
377
|
135 logger.debug('Starting code generation for {}'.format(ircode), extra=d)
|
|
136
|
381
|
137 cg.generate(ircode, output_stream)
|
377
|
138
|
|
139 if not c3b.ok:
|
|
140 diag.printErrors()
|
|
141 raise TaskError('Compile errors')
|
|
142 return output
|
|
143
|
|
144
|
385
|
145 def link(objects, layout, target):
|
381
|
146 """ Links the iterable of objects into one using the given layout """
|
377
|
147 objects = list(map(fix_object, objects))
|
383
|
148 layout = fix_layout(layout)
|
385
|
149 target = fix_target(target)
|
|
150 linker = Linker(target)
|
377
|
151 output_obj = linker.link(objects, layout)
|
|
152 return output_obj
|