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""" 11TI cgt6x is a compiler suite for TI DSPs. 12 13The toolchain does pretty weird things, and I'm sure I'm missing some of them. 14But still, the tool saves time. 15 16What 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 25TODO: 26 27- the set_platform_flags() function is not nice 28- more tests 29- broaden tool scope, if needed 30 31""" 32 33import os, re 34 35from waflib import Options, Utils, Task, TaskGen 36from waflib.Tools import c, ccroot, c_preproc 37from waflib.Configure import conf 38from waflib.TaskGen import feature, before_method 39from waflib.Tools.c import cprogram 40 41opj = os.path.join 42 43@conf 44def 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 49def 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 54def 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 60def 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 82def 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 123def 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 135def 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 162def 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 169class 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') 182def 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 189class 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 202def 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') 218def 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') 228def 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 273re_tconf_include = re.compile(r'(?P<type>utils\.importFile)\("(?P<file>.*)"\)',re.M) 274class 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 301