Changes in python/lib/gen_external.py [67cf45a:dad51ce]
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
python/lib/gen_external.py
r67cf45a rdad51ce 1 1 import distutils.ccompiler 2 import sys, os, subprocess, glob 2 import sys 3 import os 4 import subprocess 5 import glob 3 6 4 7 header = os.path.join('src', 'aubio.h') … … 9 12 """ 10 13 11 skip_objects = [12 # already in ext/13 'fft',14 'pvoc',15 'filter',16 'filterbank',17 # AUBIO_UNSTABLE18 'hist',19 'parameter',20 'scale',21 'beattracking',22 'resampler',23 'peakpicker',24 'pitchfcomb',25 'pitchmcomb',26 'pitchschmitt',27 'pitchspecacf',28 'pitchyin',29 'pitchyinfft',30 'pitchyinfast',31 'sink',32 'sink_apple_audio',33 'sink_sndfile',34 'sink_wavwrite',35 #'mfcc',36 'source',37 'source_apple_audio',38 'source_sndfile',39 'source_avcodec',40 'source_wavread',41 #'sampler',42 'audio_unit',43 'spectral_whitening', 44 ] 14 default_skip_objects = [ 15 # already in ext/ 16 'fft', 17 'pvoc', 18 'filter', 19 'filterbank', 20 # AUBIO_UNSTABLE 21 'hist', 22 'parameter', 23 'scale', 24 'beattracking', 25 'resampler', 26 'peakpicker', 27 'pitchfcomb', 28 'pitchmcomb', 29 'pitchschmitt', 30 'pitchspecacf', 31 'pitchyin', 32 'pitchyinfft', 33 'sink', 34 'sink_apple_audio', 35 'sink_sndfile', 36 'sink_wavwrite', 37 #'mfcc', 38 'source', 39 'source_apple_audio', 40 'source_sndfile', 41 'source_avcodec', 42 'source_wavread', 43 #'sampler', 44 'audio_unit', 45 'spectral_whitening', 46 ] 47 45 48 46 49 def get_preprocessor(): … … 61 64 62 65 cpp_cmd = None 63 if hasattr(compiler, 'preprocessor'): # for unixccompiler66 if hasattr(compiler, 'preprocessor'): # for unixccompiler 64 67 cpp_cmd = compiler.preprocessor 65 elif hasattr(compiler, 'compiler'): # for ccompiler68 elif hasattr(compiler, 'compiler'): # for ccompiler 66 69 cpp_cmd = compiler.compiler.split() 67 70 cpp_cmd += ['-E'] 68 elif hasattr(compiler, 'cc'): # for msvccompiler71 elif hasattr(compiler, 'cc'): # for msvccompiler 69 72 cpp_cmd = compiler.cc.split() 70 73 cpp_cmd += ['-E'] … … 74 77 cpp_cmd = os.environ.get('CC', 'cc').split() 75 78 cpp_cmd += ['-E'] 76 79 cpp_cmd += ['-x', 'c'] # force C language (emcc defaults to c++) 77 80 return cpp_cmd 78 81 79 def get_cpp_objects(header=header, usedouble=False): 82 83 def get_c_declarations(header=header, usedouble=False): 84 ''' return a dense and preprocessed string of all c declarations implied by aubio.h 85 ''' 80 86 cpp_cmd = get_preprocessor() 81 87 … … 93 99 print("Running command: {:s}".format(" ".join(cpp_cmd))) 94 100 proc = subprocess.Popen(cpp_cmd, 95 stderr=subprocess.PIPE,96 stdout=subprocess.PIPE)101 stderr=subprocess.PIPE, 102 stdout=subprocess.PIPE) 97 103 assert proc, 'Proc was none' 98 104 cpp_output = proc.stdout.read() … … 101 107 raise Exception("preprocessor output is empty:\n%s" % err_output) 102 108 elif err_output: 103 print 109 print("Warning: preprocessor produced warnings:\n%s" % err_output) 104 110 if not isinstance(cpp_output, list): 105 111 cpp_output = [l.strip() for l in cpp_output.decode('utf8').split('\n')] … … 110 116 i = 1 111 117 while 1: 112 if i >= len(cpp_output): break 113 if cpp_output[i-1].endswith(',') or cpp_output[i-1].endswith('{') or cpp_output[i].startswith('}'): 114 cpp_output[i] = cpp_output[i-1] + ' ' + cpp_output[i] 115 cpp_output.pop(i-1) 118 if i >= len(cpp_output): 119 break 120 if ('{' in cpp_output[i - 1]) and (not '}' in cpp_output[i - 1]) or (not ';' in cpp_output[i - 1]): 121 cpp_output[i] = cpp_output[i - 1] + ' ' + cpp_output[i] 122 cpp_output.pop(i - 1) 123 elif ('}' in cpp_output[i]): 124 cpp_output[i] = cpp_output[i - 1] + ' ' + cpp_output[i] 125 cpp_output.pop(i - 1) 116 126 else: 117 127 i += 1 118 128 119 typedefs = filter(lambda y: y.startswith ('typedef struct _aubio'), cpp_output) 120 129 # clean pointer notations 130 tmp = [] 131 for l in cpp_output: 132 tmp += [l.replace(' *', ' * ')] 133 cpp_output = tmp 134 135 return cpp_output 136 137 138 def get_cpp_objects_from_c_declarations(c_declarations, skip_objects=None): 139 if skip_objects == None: 140 skip_objects = default_skip_objects 141 typedefs = filter(lambda y: y.startswith('typedef struct _aubio'), c_declarations) 121 142 cpp_objects = [a.split()[3][:-1] for a in typedefs] 122 123 return cpp_output, cpp_objects 124 125 126 def analyze_cpp_output(cpp_objects, cpp_output): 143 cpp_objects_filtered = filter(lambda y: not y[6:-2] in skip_objects, cpp_objects) 144 return cpp_objects_filtered 145 146 147 def get_all_func_names_from_lib(lib, depth=0): 148 ''' return flat string of all function used in lib 149 ''' 150 res = [] 151 indent = " " * depth 152 for k, v in lib.items(): 153 if isinstance(v, dict): 154 res += get_all_func_names_from_lib(v, depth + 1) 155 elif isinstance(v, list): 156 for elem in v: 157 e = elem.split('(') 158 if len(e) < 2: 159 continue # not a function 160 fname_part = e[0].strip().split(' ') 161 fname = fname_part[-1] 162 if fname: 163 res += [fname] 164 else: 165 raise NameError('gen_lib : weird function: ' + str(e)) 166 167 return res 168 169 170 def generate_lib_from_c_declarations(cpp_objects, c_declarations): 171 ''' returns a lib from given cpp_object names 172 173 a lib is a dict grouping functions by family (onset,pitch...) 174 each eement is itself a dict of functions grouped by puposes as : 175 struct, new, del, do, get, set and other 176 ''' 127 177 lib = {} 128 178 129 179 for o in cpp_objects: 130 if o[:6] != 'aubio_': 131 continue 132 shortname = o[6:-2] 133 if shortname in skip_objects: 134 continue 180 shortname = o 181 if o[:6] == 'aubio_': 182 shortname = o[6:-2] # without aubio_ prefix and _t suffix 183 135 184 lib[shortname] = {'struct': [], 'new': [], 'del': [], 'do': [], 'get': [], 'set': [], 'other': []} 136 185 lib[shortname]['longname'] = o 137 186 lib[shortname]['shortname'] = shortname 138 for fn in cpp_output: 139 if o[:-1] in fn: 140 #print "found", o[:-1], "in", fn 187 188 fullshortname = o[:-2] # name without _t suffix 189 190 for fn in c_declarations: 191 func_name = fn.split('(')[0].strip().split(' ')[-1] 192 if func_name.startswith(fullshortname + '_') or func_name.endswith(fullshortname): 193 # print "found", shortname, "in", fn 141 194 if 'typedef struct ' in fn: 142 195 lib[shortname]['struct'].append(fn) … … 152 205 lib[shortname]['set'].append(fn) 153 206 else: 154 # print "no idea what to do about", fn207 # print "no idea what to do about", fn 155 208 lib[shortname]['other'].append(fn) 156 209 return lib 157 210 158 def print_cpp_output_results(lib, cpp_output): 159 for fn in cpp_output: 211 212 def print_c_declarations_results(lib, c_declarations): 213 for fn in c_declarations: 160 214 found = 0 161 215 for o in lib: … … 164 218 found = 1 165 219 if found == 0: 166 print 220 print("missing", fn) 167 221 168 222 for o in lib: 169 223 for family in lib[o]: 170 224 if type(lib[o][family]) == str: 171 print ( "{:15s} {:10s} {:s}".format(o, family, lib[o][family] ))225 print("{:15s} {:10s} {:s}".format(o, family, lib[o][family])) 172 226 elif len(lib[o][family]) == 1: 173 print ( "{:15s} {:10s} {:s}".format(o, family, lib[o][family][0] ))227 print("{:15s} {:10s} {:s}".format(o, family, lib[o][family][0])) 174 228 else: 175 print ( "{:15s} {:10s} {:s}".format(o, family, lib[o][family] ))229 print("{:15s} {:10s} {:s}".format(o, family, lib[o][family])) 176 230 177 231 178 232 def generate_external(header=header, output_path=output_path, usedouble=False, overwrite=True): 179 if not os.path.isdir(output_path): os.mkdir(output_path) 180 elif not overwrite: return sorted(glob.glob(os.path.join(output_path, '*.c'))) 181 182 cpp_output, cpp_objects = get_cpp_objects(header, usedouble=usedouble) 183 184 lib = analyze_cpp_output(cpp_objects, cpp_output) 185 # print_cpp_output_results(lib, cpp_output) 233 if not os.path.isdir(output_path): 234 os.mkdir(output_path) 235 elif not overwrite: 236 return sorted(glob.glob(os.path.join(output_path, '*.c'))) 237 238 c_declarations = get_c_declarations(header, usedouble=usedouble) 239 cpp_objects = get_cpp_objects_from_c_declarations(c_declarations) 240 241 lib = generate_lib_from_c_declarations(cpp_objects, c_declarations) 242 # print_c_declarations_results(lib, c_declarations) 186 243 187 244 sources_list = [] … … 192 249 for o in lib: 193 250 out = source_header 194 mapped = MappedObject(lib[o], usedouble =usedouble)251 mapped = MappedObject(lib[o], usedouble=usedouble) 195 252 out += mapped.gen_code() 196 253 output_file = os.path.join(output_path, 'gen-%s.c' % o) 197 254 with open(output_file, 'w') as f: 198 255 f.write(out) 199 print ("wrote %s" % output_file)256 print("wrote %s" % output_file) 200 257 sources_list.append(output_file) 201 258 … … 209 266 return ({pycheck_types}); 210 267 }} 211 """.format(pycheck_types =check_types)268 """.format(pycheck_types=check_types) 212 269 213 270 add_types = "".join([""" 214 271 Py_INCREF (&Py_{name}Type); 215 PyModule_AddObject(m, "{name}", (PyObject *) & Py_{name}Type);""".format(name =o) for o in lib])272 PyModule_AddObject(m, "{name}", (PyObject *) & Py_{name}Type);""".format(name=o) for o in lib]) 216 273 out += """ 217 274 … … 220 277 {add_types} 221 278 }} 222 """.format(add_types =add_types)279 """.format(add_types=add_types) 223 280 224 281 output_file = os.path.join(output_path, 'aubio-generated.c') 225 282 with open(output_file, 'w') as f: 226 283 f.write(out) 227 print ("wrote %s" % output_file)284 print("wrote %s" % output_file) 228 285 sources_list.append(output_file) 229 286 … … 243 300 int generated_objects ( void ); 244 301 void add_generated_objects( PyObject *m ); 245 """.format(objlist =objlist)302 """.format(objlist=objlist) 246 303 247 304 output_file = os.path.join(output_path, 'aubio-generated.h') 248 305 with open(output_file, 'w') as f: 249 306 f.write(out) 250 print ("wrote %s" % output_file)307 print("wrote %s" % output_file) 251 308 # no need to add header to list of sources 252 309 … … 254 311 255 312 if __name__ == '__main__': 256 if len(sys.argv) > 1: header = sys.argv[1] 257 if len(sys.argv) > 2: output_path = sys.argv[2] 313 if len(sys.argv) > 1: 314 header = sys.argv[1] 315 if len(sys.argv) > 2: 316 output_path = sys.argv[2] 258 317 generate_external(header, output_path)
Note: See TracChangeset
for help on using the changeset viewer.