Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • python/lib/gen_external.py

    r67cf45a rdad51ce  
    11import distutils.ccompiler
    2 import sys, os, subprocess, glob
     2import sys
     3import os
     4import subprocess
     5import glob
    36
    47header = os.path.join('src', 'aubio.h')
     
    912"""
    1013
    11 skip_objects = [
    12   # already in ext/
    13   'fft',
    14   'pvoc',
    15   'filter',
    16   'filterbank',
    17   # AUBIO_UNSTABLE
    18   '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   ]
     14default_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
    4548
    4649def get_preprocessor():
     
    6164
    6265    cpp_cmd = None
    63     if hasattr(compiler, 'preprocessor'): # for unixccompiler
     66    if hasattr(compiler, 'preprocessor'):  # for unixccompiler
    6467        cpp_cmd = compiler.preprocessor
    65     elif hasattr(compiler, 'compiler'): # for ccompiler
     68    elif hasattr(compiler, 'compiler'):  # for ccompiler
    6669        cpp_cmd = compiler.compiler.split()
    6770        cpp_cmd += ['-E']
    68     elif hasattr(compiler, 'cc'): # for msvccompiler
     71    elif hasattr(compiler, 'cc'):  # for msvccompiler
    6972        cpp_cmd = compiler.cc.split()
    7073        cpp_cmd += ['-E']
     
    7477        cpp_cmd = os.environ.get('CC', 'cc').split()
    7578        cpp_cmd += ['-E']
    76 
     79    cpp_cmd += ['-x', 'c']  # force C language (emcc defaults to c++)
    7780    return cpp_cmd
    7881
    79 def get_cpp_objects(header=header, usedouble=False):
     82
     83def get_c_declarations(header=header, usedouble=False):
     84    ''' return a dense and preprocessed  string of all c declarations implied by aubio.h
     85    '''
    8086    cpp_cmd = get_preprocessor()
    8187
     
    9399    print("Running command: {:s}".format(" ".join(cpp_cmd)))
    94100    proc = subprocess.Popen(cpp_cmd,
    95             stderr=subprocess.PIPE,
    96             stdout=subprocess.PIPE)
     101                            stderr=subprocess.PIPE,
     102                            stdout=subprocess.PIPE)
    97103    assert proc, 'Proc was none'
    98104    cpp_output = proc.stdout.read()
     
    101107        raise Exception("preprocessor output is empty:\n%s" % err_output)
    102108    elif err_output:
    103         print ("Warning: preprocessor produced warnings:\n%s" % err_output)
     109        print("Warning: preprocessor produced warnings:\n%s" % err_output)
    104110    if not isinstance(cpp_output, list):
    105111        cpp_output = [l.strip() for l in cpp_output.decode('utf8').split('\n')]
     
    110116    i = 1
    111117    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)
    116126        else:
    117127            i += 1
    118128
    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
     138def 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)
    121142    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
     147def 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
     170def 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    '''
    127177    lib = {}
    128178
    129179    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
    135184        lib[shortname] = {'struct': [], 'new': [], 'del': [], 'do': [], 'get': [], 'set': [], 'other': []}
    136185        lib[shortname]['longname'] = o
    137186        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
    141194                if 'typedef struct ' in fn:
    142195                    lib[shortname]['struct'].append(fn)
     
    152205                    lib[shortname]['set'].append(fn)
    153206                else:
    154                     #print "no idea what to do about", fn
     207                    # print "no idea what to do about", fn
    155208                    lib[shortname]['other'].append(fn)
    156209    return lib
    157210
    158 def print_cpp_output_results(lib, cpp_output):
    159     for fn in cpp_output:
     211
     212def print_c_declarations_results(lib, c_declarations):
     213    for fn in c_declarations:
    160214        found = 0
    161215        for o in lib:
     
    164218                    found = 1
    165219        if found == 0:
    166             print ("missing", fn)
     220            print("missing", fn)
    167221
    168222    for o in lib:
    169223        for family in lib[o]:
    170224            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]))
    172226            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]))
    174228            else:
    175                 print ( "{:15s} {:10s} {:s}".format(o, family, lib[o][family] ) )
     229                print("{:15s} {:10s} {:s}".format(o, family, lib[o][family]))
    176230
    177231
    178232def 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)
    186243
    187244    sources_list = []
     
    192249    for o in lib:
    193250        out = source_header
    194         mapped = MappedObject(lib[o], usedouble = usedouble)
     251        mapped = MappedObject(lib[o], usedouble=usedouble)
    195252        out += mapped.gen_code()
    196253        output_file = os.path.join(output_path, 'gen-%s.c' % o)
    197254        with open(output_file, 'w') as f:
    198255            f.write(out)
    199             print ("wrote %s" % output_file )
     256            print("wrote %s" % output_file)
    200257            sources_list.append(output_file)
    201258
     
    209266  return ({pycheck_types});
    210267}}
    211 """.format(pycheck_types = check_types)
     268""".format(pycheck_types=check_types)
    212269
    213270    add_types = "".join(["""
    214271  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])
    216273    out += """
    217274
     
    220277{add_types}
    221278}}
    222 """.format(add_types = add_types)
     279""".format(add_types=add_types)
    223280
    224281    output_file = os.path.join(output_path, 'aubio-generated.c')
    225282    with open(output_file, 'w') as f:
    226283        f.write(out)
    227         print ("wrote %s" % output_file )
     284        print("wrote %s" % output_file)
    228285        sources_list.append(output_file)
    229286
     
    243300int generated_objects ( void );
    244301void add_generated_objects( PyObject *m );
    245 """.format(objlist = objlist)
     302""".format(objlist=objlist)
    246303
    247304    output_file = os.path.join(output_path, 'aubio-generated.h')
    248305    with open(output_file, 'w') as f:
    249306        f.write(out)
    250         print ("wrote %s" % output_file )
     307        print("wrote %s" % output_file)
    251308        # no need to add header to list of sources
    252309
     
    254311
    255312if __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]
    258317    generate_external(header, output_path)
Note: See TracChangeset for help on using the changeset viewer.