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
|
|
15 from .target.target_list import targets
|
|
16 from .outstream import BinaryOutputStream, MasterOutputStream
|
|
17 from .outstream import LoggerOutputStream
|
|
18 from .assembler import Assembler
|
|
19 from .objectfile import ObjectFile, load_object
|
|
20 from . import DiagnosticsManager, CompilerError
|
|
21
|
|
22 def fix_target(tg):
|
|
23 """ Try to return an instance of the Target class """
|
|
24 if isinstance(tg, Target):
|
|
25 return tg
|
|
26 elif isinstance(tg, str):
|
|
27 if tg in targets:
|
|
28 return targets[tg]
|
|
29 raise TaskError('Invalid target {}'.format(tg))
|
|
30
|
|
31 def fix_file(f):
|
|
32 """ Determine if argument is a file like object or make it so! """
|
|
33 if hasattr(f, 'read'):
|
|
34 # Assume this is a file like object
|
|
35 return f
|
|
36 elif isinstance(f, str):
|
|
37 return open(f, 'r')
|
|
38 else:
|
|
39 raise TaskError('cannot use {} as input'.format(f))
|
|
40
|
|
41 def fix_object(o):
|
|
42 if isinstance(o, ObjectFile):
|
|
43 return o
|
|
44 elif isinstance(o, str):
|
|
45 with open(o, 'r') as f:
|
|
46 return load_object(f)
|
|
47 else:
|
|
48 raise TaskError('Cannot use {} as objectfile'.format(o))
|
|
49
|
|
50
|
|
51 def assemble(source, target):
|
|
52 logger = logging.getLogger('assemble')
|
|
53 target = fix_target(target)
|
|
54 source = fix_file(source)
|
|
55 output = ObjectFile()
|
|
56 assembler = Assembler(target)
|
|
57 logger.debug('Assembling into code section')
|
|
58 o2 = BinaryOutputStream(output)
|
|
59 o1 = LoggerOutputStream()
|
|
60 ostream = MasterOutputStream([o1, o2])
|
|
61 ostream.select_section('code')
|
|
62 assembler.assemble(source, ostream)
|
|
63 return output
|
|
64
|
|
65
|
|
66 def c3compile(sources, includes, target):
|
|
67 """ Compile a set of sources """
|
|
68 logger = logging.getLogger('c3c')
|
|
69 logger.debug('C3 compilation started')
|
|
70 target = fix_target(target)
|
|
71 sources = [fix_file(fn) for fn in sources]
|
|
72 includes = [fix_file(fn) for fn in includes]
|
|
73 output = ObjectFile()
|
|
74 diag = DiagnosticsManager()
|
|
75 c3b = Builder(diag, target)
|
|
76 cg = CodeGenerator(target)
|
|
77
|
|
78 o2 = BinaryOutputStream(output)
|
|
79 o1 = LoggerOutputStream()
|
|
80 o = MasterOutputStream([o1, o2])
|
|
81
|
|
82 for ircode in c3b.build(sources, includes):
|
|
83 if not ircode:
|
|
84 # Something went wrong, do not continue the code generation
|
|
85 continue
|
|
86
|
|
87 d = {'ircode':ircode}
|
|
88 logger.debug('Verifying code {}'.format(ircode), extra=d)
|
|
89 Verifier().verify(ircode)
|
|
90
|
|
91 # Optimization passes:
|
|
92 CleanPass().run(ircode)
|
|
93 Verifier().verify(ircode)
|
|
94 RemoveAddZero().run(ircode)
|
|
95 Verifier().verify(ircode)
|
|
96 CleanPass().run(ircode)
|
|
97 Verifier().verify(ircode)
|
|
98
|
|
99 # Code generation:
|
|
100 d = {'ircode':ircode}
|
|
101 logger.debug('Starting code generation for {}'.format(ircode), extra=d)
|
|
102
|
|
103 cg.generate(ircode, o)
|
|
104
|
|
105 if not c3b.ok:
|
|
106 diag.printErrors()
|
|
107 raise TaskError('Compile errors')
|
|
108 return output
|
|
109
|
|
110
|
|
111 def link(objects, layout):
|
|
112 objects = list(map(fix_object, objects))
|
|
113 linker = Linker()
|
|
114 output_obj = linker.link(objects, layout)
|
|
115 return output_obj
|