Package instant :: Module codegeneration
[hide private]
[frames] | no frames]

Source Code for Module instant.codegeneration

  1  """This module contains helper functions for code generation.""" 
  2   
  3  import re, os 
  4  from output import instant_assert, instant_warning, instant_debug, write_file 
  5   
  6   
7 -def mapstrings(format, sequence):
8 return "\n".join(format % i for i in sequence)
9 10
11 -def reindent(code):
12 '''Reindent a multiline string to allow easier to read syntax. 13 14 Each line will be indented relative to the first non-empty line. 15 Start the first line without text like shown in this example:: 16 17 code = reindent(""" 18 Foo 19 Bar 20 Blatti 21 Ping 22 """) 23 24 makes all indentation relative to Foo. 25 ''' 26 lines = code.split("\n") 27 space = "" 28 # Get initial spaces from first non-empty line: 29 for l in lines: 30 if l: 31 r = re.search(r"^( [ ]*)", l) 32 if r is not None: 33 space = r.groups()[0] 34 break 35 if not space: 36 return code 37 n = len(space) 38 instant_assert(space == " "*n, "Logic breach in reindent.") 39 return "\n".join(re.sub(r"^%s" % space, "", l) for l in lines)
40 41
42 -def write_interfacefile(filename, modulename, code, init_code, 43 additional_definitions, additional_declarations, 44 system_headers, local_headers, wrap_headers, arrays):
45 """Generate a SWIG interface file. Intended for internal library use. 46 47 The input arguments are as follows: 48 - modulename (Name of the module) 49 - code (Code to be wrapped) 50 - init_code (Code to put in the init section of the interface file) 51 - additional_definitions (Definitions to be placed in initial block with 52 C code as well as in the main section of the SWIG interface file) 53 - additional_declarations (Declarations to be placed in the main section 54 of the SWIG interface file) 55 - system_headers (A list of system headers with declarations needed by the wrapped code) 56 - local_headers (A list of local headers with declarations needed by the wrapped code) 57 - wrap_headers (A list of local headers that will be included in the code and wrapped by SWIG) 58 - arrays (A nested list, the inner lists describing the different arrays) 59 60 The result of this function is that a SWIG interface with 61 the name modulename.i is written to the current directory. 62 """ 63 instant_debug("Generating SWIG interface file '%s'." % filename) 64 65 # create typemaps 66 typemaps = "" 67 valid_types = ['float', 'double', 'short', 'int', 'long', 68 'unsigned short', 'unsigned int', 'unsigned long'] 69 DATA_TYPE = 'double' 70 for a in arrays: 71 if type(a) == tuple: 72 a = list(a) 73 for vt in valid_types: 74 if vt in a: 75 DATA_TYPE = vt 76 a.remove(vt) 77 if 'in' in a: 78 # input arrays 79 a.remove('in') 80 instant_assert(len(a) > 1 and len(a) < 5, "Wrong number of elements in input array") 81 if len(a) == 2: 82 # 1-dimensional arrays, i.e. vectors 83 typemaps += reindent(""" 84 %%apply (int DIM1, %(dtype)s* IN_ARRAY1) {(int %(n1)s, %(dtype)s* %(array)s)}; 85 """ % { 'n1' : a[0], 'array' : a[1], 'dtype' : DATA_TYPE }) 86 elif len(a) == 3: 87 # 2-dimensional arrays, i.e. matrices 88 typemaps += reindent(""" 89 %%apply (int DIM1, int DIM2, %(dtype)s* IN_ARRAY2) {(int %(n1)s, int %(n2)s, %(dtype)s* %(array)s)}; 90 """ % { 'n1' : a[0], 'n2' : a[1], 'array' : a[2], 'dtype' : DATA_TYPE }) 91 else: 92 # 3-dimensional arrays, i.e. tensors 93 typemaps += reindent(""" 94 %%apply (int DIM1, int DIM2, int DIM3, %(dtype)s* IN_ARRAY3) {(int %(n1)s, int %(n2)s, int %(n3)s, %(dtype)s* %(array)s)}; 95 """ % { 'n1' : a[0], 'n2' : a[1], 'n3' : a[2], 'array' : a[3], 'dtype' : DATA_TYPE }) 96 elif 'out' in a: 97 # output arrays 98 a.remove('out') 99 instant_assert(len(a) == 2, "Output array must be 1-dimensional") 100 # 1-dimensional arrays, i.e. vectors 101 typemaps += reindent(""" 102 %%apply (int DIM1, %(dtype)s* ARGOUT_ARRAY1) {(int %(n1)s, %(dtype)s* %(array)s)}; 103 """ % { 'n1' : a[0], 'array' : a[1], 'dtype' : DATA_TYPE }) 104 else: 105 # in-place arrays 106 instant_assert(len(a) > 1 and len(a) < 5, "Wrong number of elements in output array") 107 if 'multi' in a: 108 # n-dimensional arrays, i.e. tensors > 3-dimensional 109 a.remove('multi') 110 typemaps += reindent(""" 111 %%typemap(in) (int %(n)s,int* %(ptv)s,%(dtype)s* %(array)s){ 112 if (!PyArray_Check($input)) { 113 PyErr_SetString(PyExc_TypeError, "Not a NumPy array"); 114 return NULL; ; 115 } 116 PyArrayObject* pyarray; 117 pyarray = (PyArrayObject*)$input; 118 $1 = int(pyarray->nd); 119 int* dims = new int($1); 120 for (int d=0; d<$1; d++) { 121 dims[d] = int(pyarray->dimensions[d]); 122 } 123 124 $2 = dims; 125 $3 = (%(dtype)s*)pyarray->data; 126 } 127 %%typemap(freearg) (int %(n)s,int* %(ptv)s,%(dtype)s* %(array)s){ 128 // deleting dims 129 delete $2; 130 } 131 """ % { 'n' : a[0] , 'ptv' : a[1], 'array' : a[2], 'dtype' : DATA_TYPE }) 132 elif len(a) == 2: 133 # 1-dimensional arrays, i.e. vectors 134 typemaps += reindent(""" 135 %%apply (int DIM1, %(dtype)s* INPLACE_ARRAY1) {(int %(n1)s, %(dtype)s* %(array)s)}; 136 """ % { 'n1' : a[0], 'array' : a[1], 'dtype' : DATA_TYPE }) 137 elif len(a) == 3: 138 # 2-dimensional arrays, i.e. matrices 139 typemaps += reindent(""" 140 %%apply (int DIM1, int DIM2, %(dtype)s* INPLACE_ARRAY2) {(int %(n1)s, int %(n2)s, %(dtype)s* %(array)s)}; 141 """ % { 'n1' : a[0], 'n2' : a[1], 'array' : a[2], 'dtype' : DATA_TYPE }) 142 else: 143 # 3-dimensional arrays, i.e. tensors 144 typemaps += reindent(""" 145 %%apply (int DIM1, int DIM2, int DIM3, %(dtype)s* INPLACE_ARRAY3) {(int %(n1)s, int %(n2)s, int %(n3)s, %(dtype)s* %(array)s)}; 146 """ % { 'n1' : a[0], 'n2' : a[1], 'n3' : a[2], 'array' : a[3], 'dtype' : DATA_TYPE}) 147 # end 148 # end if 149 # end for 150 151 system_headers_code = mapstrings('#include <%s>', system_headers) 152 local_headers_code = mapstrings('#include "%s"', local_headers) 153 wrap_headers_code1 = mapstrings('#include "%s"', wrap_headers) 154 wrap_headers_code2 = mapstrings('%%include "%s"', wrap_headers) 155 156 numpy_i_include = '' 157 if arrays: 158 numpy_i_include = r'%include "numpy.i"' 159 160 interface_string = reindent(""" 161 %%module %(modulename)s 162 //%%module (directors="1") %(modulename)s 163 164 //%%feature("director"); 165 166 %%{ 167 #include <iostream> 168 %(additional_definitions)s 169 %(system_headers_code)s 170 %(local_headers_code)s 171 %(wrap_headers_code1)s 172 %(code)s 173 %%} 174 175 //%%feature("autodoc", "1"); 176 %(numpy_i_include)s 177 178 %%init%%{ 179 %(init_code)s 180 %%} 181 182 %(additional_definitions)s 183 %(additional_declarations)s 184 %(wrap_headers_code2)s 185 //%(typemaps)s 186 %(code)s; 187 188 """ % locals()) 189 190 write_file(filename, interface_string) 191 instant_debug("Done generating interface file.")
192 193
194 -def write_setup(filename, modulename, csrcs, cppsrcs, local_headers, include_dirs, library_dirs, libraries, swig_include_dirs, swigargs, cppargs, lddargs):
195 """Generate a setup.py file. Intended for internal library use.""" 196 instant_debug("Generating %s." % filename) 197 198 swig_include_dirs.append(os.path.join(os.path.dirname(__file__), 'swig')) 199 200 # Handle arguments 201 swigfilename = "%s.i" % modulename 202 wrapperfilename = "%s_wrap.cxx" % modulename 203 204 # Treat C and C++ files in the same way for now 205 cppsrcs = cppsrcs + csrcs + [wrapperfilename] 206 207 swig_args = "" 208 if swigargs: 209 swig_args = " ".join(swigargs) 210 211 compile_args = "" 212 if cppargs: 213 compile_args = ", extra_compile_args=%r" % cppargs 214 215 link_args = "" 216 if lddargs: 217 link_args = ", extra_link_args=%r" % lddargs 218 219 swig_include_dirs = " ".join("-I%s"%d for d in swig_include_dirs) 220 if len(local_headers) > 0: 221 swig_include_dirs += " -I.." 222 223 # Generate code 224 code = reindent(""" 225 import os 226 from distutils.core import setup, Extension 227 name = '%s' 228 swig_cmd =r'swig -python %s %s %s' 229 os.system(swig_cmd) 230 sources = %s 231 setup(name = '%s', 232 ext_modules = [Extension('_' + '%s', 233 sources, 234 include_dirs=%s, 235 library_dirs=%s, 236 libraries=%s %s %s)]) 237 """ % (modulename, swig_include_dirs, swig_args, swigfilename, cppsrcs, 238 modulename, modulename, include_dirs, library_dirs, libraries, compile_args, link_args)) 239 240 write_file(filename, code) 241 instant_debug("Done writing setup.py file.")
242 243
244 -def _test_write_interfacefile():
245 modulename = "testmodule" 246 code = "void foo() {}" 247 init_code = "/* custom init code */" 248 additional_definitions = "/* custom definitions */" 249 additional_declarations = "/* custom declarations */" 250 system_headers = ["system_header1.h", "system_header2.h"] 251 local_headers = ["local_header1.h", "local_header2.h"] 252 wrap_headers = ["wrap_header1.h", "wrap_header2.h"] 253 arrays = [["length1", "array1"], ["dims", "lengths", "array2"]] 254 255 write_interfacefile("%s.i" % modulename, modulename, code, init_code, additional_definitions, additional_declarations, system_headers, local_headers, wrap_headers, arrays) 256 print "".join(open("%s.i" % modulename).readlines())
257 258
259 -def _test_write_setup():
260 modulename = "testmodule" 261 csrcs = ["csrc1.c", "csrc2.c"] 262 cppsrcs = ["cppsrc1.cpp", "cppsrc2.cpp"] 263 local_headers = ["local_header1.h", "local_header2.h"] 264 include_dirs = ["includedir1", "includedir2"] 265 library_dirs = ["librarydir1", "librarydir2"] 266 libraries = ["lib1", "lib2"] 267 swig_include_dirs = ["swigdir1", "swigdir2"], 268 swigargs = ["-Swigarg1", "-Swigarg2"] 269 cppargs = ["-cpparg1", "-cpparg2"] 270 lddargs = ["-Lddarg1", "-Lddarg2"] 271 272 write_setup("setup.py", modulename, csrcs, cppsrcs, local_headers, include_dirs, library_dirs, libraries, swig_include_dirs, swigargs, cppargs, lddargs) 273 print "".join(open("setup.py").readlines())
274 275 276 if __name__ == "__main__": 277 _test_write_interfacefile() 278 print "\n"*3 279 _test_write_setup() 280