f43a7ea5cb1c8ecfcc94cbb1677aafac44f04c1b
[samba.git] / third_party / waf / waflib / extras / ticgt.py
1 #!/usr/bin/env python
2 # encoding: utf-8
3
4 # Texas Instruments code generator support (experimental)
5 # When reporting issues, please directly assign the bug to the maintainer.
6
7 __author__ = __maintainer__ = "Jérôme Carretero <cJ-waf@zougloub.eu>"
8 __copyright__ = "Jérôme Carretero, 2012"
9
10 """
11 TI cgt6x is a compiler suite for TI DSPs.
12
13 The toolchain does pretty weird things, and I'm sure I'm missing some of them.
14 But still, the tool saves time.
15
16 What this tool does is:
17
18 - create a TI compiler environment
19 - create TI compiler features, to handle some specifics about this compiler
20   It has a few idiosyncracies, such as not giving the liberty of the .o file names
21 - automatically activate them when using the TI compiler
22 - handle the tconf tool
23   The tool
24
25 TODO:
26
27 - the set_platform_flags() function is not nice
28 - more tests
29 - broaden tool scope, if needed
30
31 """
32
33 import os, re
34
35 from waflib import Options, Utils, Task, TaskGen
36 from waflib.Tools import c, ccroot, c_preproc
37 from waflib.Configure import conf
38 from waflib.TaskGen import feature, before_method
39 from waflib.Tools.c import cprogram
40
41 opj = os.path.join
42
43 @conf
44 def find_ticc(conf):
45         conf.find_program(['cl6x'], var='CC', path_list=opj(getattr(Options.options, 'ti-cgt-dir', ""), 'bin'))
46         conf.env.CC_NAME = 'ticc'
47
48 @conf
49 def find_tild(conf):
50         conf.find_program(['lnk6x'], var='LINK_CC', path_list=opj(getattr(Options.options, 'ti-cgt-dir', ""), 'bin'))
51         conf.env.LINK_CC_NAME = 'tild'
52
53 @conf
54 def find_tiar(conf):
55         conf.find_program(['ar6x'], var='AR', path_list=opj(getattr(Options.options, 'ti-cgt-dir', ""), 'bin'))
56         conf.env.AR_NAME = 'tiar'
57         conf.env.ARFLAGS = 'qru'
58
59 @conf
60 def ticc_common_flags(conf):
61         v = conf.env
62
63         if not v['LINK_CC']:
64                 v['LINK_CC'] = v['CC']
65         v['CCLNK_SRC_F']         = []
66         v['CCLNK_TGT_F']         = ['-o']
67         v['CPPPATH_ST']   = '-I%s'
68         v['DEFINES_ST']   = '-d%s'
69
70         v['LIB_ST']           = '-l%s' # template for adding libs
71         v['LIBPATH_ST']   = '-i%s' # template for adding libpaths
72         v['STLIB_ST']       = '-l=%s.lib'
73         v['STLIBPATH_ST']       = '-i%s'
74
75         # program
76         v['cprogram_PATTERN']    = '%s.out'
77
78         # static lib
79         #v['LINKFLAGS_cstlib']    = ['-Wl,-Bstatic']
80         v['cstlib_PATTERN']      = '%s.lib'
81
82 def configure(conf):
83         v = conf.env
84         v.TI_CGT_DIR = getattr(Options.options, 'ti-cgt-dir', "")
85         v.TI_DSPLINK_DIR = getattr(Options.options, 'ti-dsplink-dir', "")
86         v.TI_BIOSUTILS_DIR = getattr(Options.options, 'ti-biosutils-dir', "")
87         v.TI_DSPBIOS_DIR = getattr(Options.options, 'ti-dspbios-dir', "")
88         v.TI_XDCTOOLS_DIR = getattr(Options.options, 'ti-xdctools-dir', "")
89         conf.find_ticc()
90         conf.find_tiar()
91         conf.find_tild()
92         conf.ticc_common_flags()
93         conf.cc_load_tools()
94         conf.cc_add_flags()
95         conf.link_add_flags()
96         conf.find_program(['tconf'], var='TCONF', path_list=v.TI_XDCTOOLS_DIR)
97
98         conf.env.TCONF_INCLUDES += [
99          opj(conf.env.TI_DSPBIOS_DIR, 'packages'),
100         ]
101
102         conf.env.INCLUDES += [
103          opj(conf.env.TI_CGT_DIR, 'include'),
104         ]
105
106         conf.env.LIBPATH += [
107          opj(conf.env.TI_CGT_DIR, "lib"),
108         ]
109
110         conf.env.INCLUDES_DSPBIOS += [
111          opj(conf.env.TI_DSPBIOS_DIR, 'packages', 'ti', 'bios', 'include'),
112         ]
113
114         conf.env.LIBPATH_DSPBIOS += [
115          opj(conf.env.TI_DSPBIOS_DIR, 'packages', 'ti', 'bios', 'lib'),
116         ]
117
118         conf.env.INCLUDES_DSPLINK += [
119          opj(conf.env.TI_DSPLINK_DIR, 'dsplink', 'dsp', 'inc'),
120         ]
121
122 @conf
123 def ti_set_debug(cfg, debug=1):
124         """
125         Sets debug flags for the compiler.
126
127         TODO:
128         - for each TI CFLAG/INCLUDES/LINKFLAGS/LIBPATH replace RELEASE by DEBUG
129         - -g --no_compress
130         """
131         if debug:
132                 cfg.env.CFLAGS += "-d_DEBUG -dDEBUG -dDDSP_DEBUG".split()
133
134 @conf
135 def ti_dsplink_set_platform_flags(cfg, splat, dsp, dspbios_ver, board):
136         """
137         Sets the INCLUDES, LINKFLAGS for DSPLINK and TCONF_INCLUDES
138         For the specific hardware.
139
140         Assumes that DSPLINK was built in its own folder.
141
142         :param splat: short platform name (eg. OMAPL138)
143         :param dsp: DSP name (eg. 674X)
144         :param dspbios_ver: string identifying DspBios version (eg. 5.XX)
145         :param board: board name (eg. OMAPL138GEM)
146
147         """
148         d1 = opj(cfg.env.TI_DSPLINK_DIR, 'dsplink', 'dsp', 'inc', 'DspBios', dspbios_ver)
149         d = opj(cfg.env.TI_DSPLINK_DIR, 'dsplink', 'dsp', 'inc', 'DspBios', dspbios_ver, board)
150         cfg.env.TCONF_INCLUDES += [d1, d]
151         cfg.env.INCLUDES_DSPLINK += [
152          opj(cfg.env.TI_DSPLINK_DIR, 'dsplink', 'dsp', 'inc', dsp),
153          d,
154         ]
155
156         cfg.env.LINKFLAGS_DSPLINK += [
157          opj(cfg.env.TI_DSPLINK_DIR, 'dsplink', 'dsp', 'export', 'BIN', 'DspBios', splat, board+'_0', 'RELEASE', 'dsplink%s.lib' % x)
158          for x in ('', 'pool', 'mpcs', 'mplist', 'msg', 'data', 'notify', 'ringio')
159         ]
160
161
162 def options(opt):
163         opt.add_option('--with-ti-cgt', type='string', dest='ti-cgt-dir', help = 'Specify alternate cgt root folder', default="")
164         opt.add_option('--with-ti-biosutils', type='string', dest='ti-biosutils-dir', help = 'Specify alternate biosutils folder', default="")
165         opt.add_option('--with-ti-dspbios', type='string', dest='ti-dspbios-dir', help = 'Specify alternate dspbios folder', default="")
166         opt.add_option('--with-ti-dsplink', type='string', dest='ti-dsplink-dir', help = 'Specify alternate dsplink folder', default="")
167         opt.add_option('--with-ti-xdctools', type='string', dest='ti-xdctools-dir', help = 'Specify alternate xdctools folder', default="")
168
169 class ti_cprogram(cprogram):
170         """
171         Link object files into a c program
172         
173         Changes:
174
175         - the linked executable to have a relative path (because we can)
176         - put the LIBPATH first
177         """
178         run_str = '${LINK_CC} ${LIBPATH_ST:LIBPATH} ${LIB_ST:LIB} ${LINKFLAGS} ${CCLNK_SRC_F}${SRC} ${CCLNK_TGT_F}${TGT[0].bldpath()} ${RPATH_ST:RPATH} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${FRAMEWORK_ST:FRAMEWORK} ${ARCH_ST:ARCH} ${STLIB_MARKER} ${STLIBPATH_ST:STLIBPATH} ${STLIB_ST:STLIB} ${SHLIB_MARKER} '
179
180 @feature("c")
181 @before_method('apply_link')
182 def use_ti_cprogram(self):
183         """
184         Automatically uses ti_cprogram link process
185         """
186         if 'cprogram' in self.features and self.env.CC_NAME == 'ticc':
187                 self.features.insert(0, "ti_cprogram")
188
189 class ti_c(Task.Task):
190         """
191         Compile task for the TI codegen compiler
192
193         This compiler does not allow specifying the output file name, only the output path.
194
195         """
196         "Compile C files into object files"
197         run_str = '${CC} ${ARCH_ST:ARCH} ${CFLAGS} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${SRC} -c ${OUT} ${CPPFLAGS}'
198         vars    = ['CCDEPS'] # unused variable to depend on, just in case
199         ext_in  = ['.h'] # set the build order easily by using ext_out=['.h']
200         scan    = c_preproc.scan
201
202 def create_compiled_task(self, name, node):
203         """
204         Overrides ccroot.create_compiled_task to support ti_c
205         """
206         out = '%s' % (node.change_ext('.obj').name)
207         if self.env.CC_NAME == 'ticc':
208                 name = 'ti_c'
209         task = self.create_task(name, node, node.parent.find_or_declare(out))
210         self.env.OUT = '-fr%s' % (node.parent.get_bld().abspath())
211         try:
212                 self.compiled_tasks.append(task)
213         except AttributeError:
214                 self.compiled_tasks = [task]
215         return task
216
217 @TaskGen.extension('.c')
218 def c_hook(self, node):
219         "Bind the c file extension to the creation of a :py:class:`waflib.Tools.c.c` instance"
220         if self.env.CC_NAME == 'ticc':
221                 return create_compiled_task(self, 'ti_c', node)
222         else:
223                 return self.create_compiled_task('c', node)
224
225
226 @feature("ti-tconf")
227 @before_method('process_source')
228 def apply_tconf(self):
229         sources = [x.get_src() for x in self.to_nodes(self.source, path=self.path.get_src())]
230         node = sources[0]
231         assert(sources[0].name.endswith(".tcf"))
232         if len(sources) > 1:
233                 assert(sources[1].name.endswith(".cmd"))
234
235         target = getattr(self, 'target', self.source)
236         target_node = node.get_bld().parent.find_or_declare(node.name)
237         
238         procid = "%d" % int(getattr(self, 'procid', 0))
239
240         importpaths = []
241         includes = Utils.to_list(getattr(self, 'includes', []))
242         for x in includes + self.env.TCONF_INCLUDES:
243                 if x == os.path.abspath(x):
244                         importpaths.append(x)
245                 else:
246                         relpath = self.path.find_node(x).path_from(target_node.parent)
247                         importpaths.append(relpath)
248
249         task = self.create_task('ti_tconf', sources, target_node.change_ext('.cdb'))
250         task.path = self.path
251         task.includes = includes
252         task.cwd = target_node.parent.abspath()
253         task.env = self.env.derive()
254         task.env["TCONFSRC"] = node.path_from(target_node.parent)
255         task.env["TCONFINC"] = '-Dconfig.importPath=%s' % ";".join(importpaths)
256         task.env['TCONFPROGNAME'] = '-Dconfig.programName=%s' % target
257         task.env['PROCID'] = procid
258         task.outputs = [
259          target_node.change_ext("cfg_c.c"),
260          target_node.change_ext("cfg.s62"),
261          target_node.change_ext("cfg.cmd"),
262         ]
263
264         create_compiled_task(self, 'ti_c', task.outputs[1])
265         ctask = create_compiled_task(self, 'ti_c', task.outputs[0])
266         ctask.env = self.env.derive()
267
268         self.add_those_o_files(target_node.change_ext("cfg.cmd"))
269         if len(sources) > 1:
270                 self.add_those_o_files(sources[1])
271         self.source = []
272
273 re_tconf_include = re.compile(r'(?P<type>utils\.importFile)\("(?P<file>.*)"\)',re.M)
274 class ti_tconf(Task.Task):
275         run_str = '${TCONF} ${TCONFINC} ${TCONFPROGNAME} ${TCONFSRC} ${PROCID}'
276         color   = 'PINK'
277
278         def scan(self):
279                 includes = Utils.to_list(getattr(self, 'includes', []))
280
281                 def deps(node):
282                         nodes, names = [], []
283                         if node:
284                                 code = Utils.readf(node.abspath())
285                                 for match in re_tconf_include.finditer(code):
286                                         path = match.group('file')
287                                         if path:
288                                                 for x in includes:
289                                                         filename = opj(x, path)
290                                                         fi = self.path.find_resource(filename)
291                                                         if fi:
292                                                                 subnodes, subnames = deps(fi)
293                                                                 nodes += subnodes
294                                                                 names += subnames
295                                                                 nodes.append(fi)
296                                                                 names.append(path)
297                                                                 break
298                         return nodes, names
299                 return deps(self.inputs[0])
300