1#!/usr/bin/python 2# -*- coding: utf-8 -*- 3# Halide code generation tool 4 5__author__ = __maintainer__ = "Jérôme Carretero <cJ-waf@zougloub.eu>" 6__copyright__ = "Jérôme Carretero, 2014" 7 8""" 9 10Tool to run `Halide <http://halide-lang.org>`_ code generators. 11 12Usage:: 13 14 bld( 15 name='pipeline', 16 # ^ Reference this in use="..." for things using the generated code 17 #target=['pipeline.o', 'pipeline.h'] 18 # ^ by default, name.{o,h} is added, but you can set the outputs here 19 features='halide', 20 halide_env="HL_TRACE=1 HL_TARGET=host-opencl-gpu_debug", 21 # ^ Environment passed to the generator, 22 # can be a dict, k/v list, or string. 23 args=[], 24 # ^ Command-line arguments to the generator (optional), 25 # eg. to give parameters to the scheduling 26 source='pipeline_gen', 27 # ^ Name of the source executable 28 ) 29 30 31Known issues: 32 33 34- Currently only supports Linux (no ".exe") 35 36- Doesn't rerun on input modification when input is part of a build 37 chain, and has been modified externally. 38 39""" 40 41import os 42from waflib import Task, Utils, Options, TaskGen, Errors 43 44class run_halide_gen(Task.Task): 45 color = 'CYAN' 46 vars = ['HALIDE_ENV', 'HALIDE_ARGS'] 47 run_str = "${SRC[0].abspath()} ${HALIDE_ARGS}" 48 def __str__(self): 49 stuff = "halide" 50 stuff += ("[%s]" % (",".join( 51 ('%s=%s' % (k,v)) for k, v in sorted(self.env.env.items())))) 52 return Task.Task.__str__(self).replace(self.__class__.__name__, 53 stuff) 54 55@TaskGen.feature('halide') 56@TaskGen.before_method('process_source') 57def halide(self): 58 Utils.def_attrs(self, 59 args=[], 60 halide_env={}, 61 ) 62 63 bld = self.bld 64 65 env = self.halide_env 66 try: 67 if isinstance(env, str): 68 env = dict(x.split('=') for x in env.split()) 69 elif isinstance(env, list): 70 env = dict(x.split('=') for x in env) 71 assert isinstance(env, dict) 72 except Exception as e: 73 if not isinstance(e, ValueError) \ 74 and not isinstance(e, AssertionError): 75 raise 76 raise Errors.WafError( 77 "halide_env must be under the form" \ 78 " {'HL_x':'a', 'HL_y':'b'}" \ 79 " or ['HL_x=y', 'HL_y=b']" \ 80 " or 'HL_x=y HL_y=b'") 81 82 src = self.to_nodes(self.source) 83 assert len(src) == 1, "Only one source expected" 84 src = src[0] 85 86 args = Utils.to_list(self.args) 87 88 def change_ext(src, ext): 89 # Return a node with a new extension, in an appropriate folder 90 name = src.name 91 xpos = src.name.rfind('.') 92 if xpos == -1: 93 xpos = len(src.name) 94 newname = name[:xpos] + ext 95 if src.is_child_of(bld.bldnode): 96 node = src.get_src().parent.find_or_declare(newname) 97 else: 98 node = bld.bldnode.find_or_declare(newname) 99 return node 100 101 def to_nodes(self, lst, path=None): 102 tmp = [] 103 path = path or self.path 104 find = path.find_or_declare 105 106 if isinstance(lst, self.path.__class__): 107 lst = [lst] 108 109 for x in Utils.to_list(lst): 110 if isinstance(x, str): 111 node = find(x) 112 else: 113 node = x 114 tmp.append(node) 115 return tmp 116 117 tgt = to_nodes(self, self.target) 118 if not tgt: 119 tgt = [change_ext(src, '.o'), change_ext(src, '.h')] 120 cwd = tgt[0].parent.abspath() 121 task = self.create_task('run_halide_gen', src, tgt, cwd=cwd) 122 task.env.append_unique('HALIDE_ARGS', args) 123 if task.env.env == []: 124 task.env.env = {} 125 task.env.env.update(env) 126 task.env.HALIDE_ENV = " ".join(("%s=%s" % (k,v)) for (k,v) in sorted(env.items())) 127 task.env.HALIDE_ARGS = args 128 129 try: 130 self.compiled_tasks.append(task) 131 except AttributeError: 132 self.compiled_tasks = [task] 133 self.source = [] 134 135def configure(conf): 136 if Options.options.halide_root is None: 137 conf.check_cfg(package='Halide', args='--cflags --libs') 138 else: 139 halide_root = Options.options.halide_root 140 conf.env.INCLUDES_HALIDE = [ os.path.join(halide_root, "include") ] 141 conf.env.LIBPATH_HALIDE = [ os.path.join(halide_root, "lib") ] 142 conf.env.LIB_HALIDE = ["Halide"] 143 144 # You might want to add this, while upstream doesn't fix it 145 #conf.env.LIB_HALIDE += ['ncurses', 'dl', 'pthread'] 146 147def options(opt): 148 opt.add_option('--halide-root', 149 help="path to Halide include and lib files", 150 ) 151 152