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
|
381
|
17 from .outstream import BinaryAndLoggingStream
|
377
|
18 from .objectfile import ObjectFile, load_object
|
|
19 from . import DiagnosticsManager, CompilerError
|
383
|
20 from .tasks import TaskError
|
381
|
21
|
385
|
22
|
377
|
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 raise TaskError('Invalid target {}'.format(tg))
|
|
31
|
381
|
32
|
377
|
33 def fix_file(f):
|
|
34 """ Determine if argument is a file like object or make it so! """
|
|
35 if hasattr(f, 'read'):
|
|
36 # Assume this is a file like object
|
|
37 return f
|
|
38 elif isinstance(f, str):
|
|
39 return open(f, 'r')
|
|
40 else:
|
|
41 raise TaskError('cannot use {} as input'.format(f))
|
|
42
|
381
|
43
|
377
|
44 def fix_object(o):
|
|
45 if isinstance(o, ObjectFile):
|
|
46 return o
|
|
47 elif isinstance(o, str):
|
|
48 with open(o, 'r') as f:
|
|
49 return load_object(f)
|
|
50 else:
|
|
51 raise TaskError('Cannot use {} as objectfile'.format(o))
|
|
52
|
|
53
|
383
|
54 def fix_layout(l):
|
|
55 if isinstance(l, Layout):
|
|
56 return l
|
|
57 elif hasattr(l, 'read'):
|
|
58 # Assume file handle
|
|
59 return load_layout(l)
|
|
60 elif isinstance(l, str):
|
|
61 with open(l, 'r') as f:
|
|
62 return load_layout(f)
|
|
63 else:
|
|
64 raise TaskError('Cannot use {} as layout'.format(l))
|
|
65
|
|
66
|
377
|
67 def assemble(source, target):
|
381
|
68 """ Invoke the assembler on the given source, returns an object containing
|
|
69 the output. """
|
377
|
70 logger = logging.getLogger('assemble')
|
|
71 target = fix_target(target)
|
|
72 source = fix_file(source)
|
|
73 output = ObjectFile()
|
381
|
74 assembler = target.assembler
|
377
|
75 logger.debug('Assembling into code section')
|
381
|
76 ostream = BinaryAndLoggingStream(output)
|
377
|
77 ostream.select_section('code')
|
386
|
78 assembler.prepare()
|
377
|
79 assembler.assemble(source, ostream)
|
381
|
80 assembler.flush()
|
377
|
81 return output
|
|
82
|
|
83
|
|
84 def c3compile(sources, includes, target):
|
381
|
85 """ Compile a set of sources for the given target """
|
377
|
86 logger = logging.getLogger('c3c')
|
|
87 logger.debug('C3 compilation started')
|
|
88 target = fix_target(target)
|
|
89 sources = [fix_file(fn) for fn in sources]
|
|
90 includes = [fix_file(fn) for fn in includes]
|
|
91 output = ObjectFile()
|
|
92 diag = DiagnosticsManager()
|
|
93 c3b = Builder(diag, target)
|
|
94 cg = CodeGenerator(target)
|
|
95
|
381
|
96 output_stream = BinaryAndLoggingStream(output)
|
377
|
97
|
|
98 for ircode in c3b.build(sources, includes):
|
|
99 if not ircode:
|
|
100 # Something went wrong, do not continue the code generation
|
|
101 continue
|
|
102
|
|
103 d = {'ircode':ircode}
|
|
104 logger.debug('Verifying code {}'.format(ircode), extra=d)
|
|
105 Verifier().verify(ircode)
|
|
106
|
|
107 # Optimization passes:
|
|
108 CleanPass().run(ircode)
|
|
109 Verifier().verify(ircode)
|
|
110 RemoveAddZero().run(ircode)
|
|
111 Verifier().verify(ircode)
|
|
112 CleanPass().run(ircode)
|
|
113 Verifier().verify(ircode)
|
|
114
|
|
115 # Code generation:
|
|
116 d = {'ircode':ircode}
|
|
117 logger.debug('Starting code generation for {}'.format(ircode), extra=d)
|
|
118
|
381
|
119 cg.generate(ircode, output_stream)
|
377
|
120
|
|
121 if not c3b.ok:
|
|
122 diag.printErrors()
|
|
123 raise TaskError('Compile errors')
|
|
124 return output
|
|
125
|
|
126
|
385
|
127 def link(objects, layout, target):
|
381
|
128 """ Links the iterable of objects into one using the given layout """
|
377
|
129 objects = list(map(fix_object, objects))
|
383
|
130 layout = fix_layout(layout)
|
385
|
131 target = fix_target(target)
|
|
132 linker = Linker(target)
|
377
|
133 output_obj = linker.link(objects, layout)
|
|
134 return output_obj
|
381
|
135
|