#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from __future__ import print_function

import sys
import os.path

default_libs = ['libav', 'libsamplerate', 'taglib', 'yaml', 'fftw', 'libchromaprint']

# LIB_KEY: package_name
lib_map = {
    'EIGEN3': 'eigen3',
    'AVCODEC': 'libavcodec',
    'AVFORMAT': 'libavformat',
    'AVUTIL': 'libavutil',
    'SWRESAMPLE': 'libswresample',
    'SAMPLERATE': 'samplerate',
    'TAGLIB': 'taglib',
    'YAML': 'yaml-0.1',
    'FFTW': 'fftw3f',
    'LIBCHROMAPRINT': 'libchromaprint',
    'GAIA2': 'gaia2',
    'TENSORFLOW': 'tensorflow'}


def options(ctx):
    ctx.add_option('--with-python', action='store_true',
                   dest='WITH_PYTHON', default=False,
                   help='build the python bindings')
    ctx.add_option('--with-examples', action='store_true',
                   dest='WITH_EXAMPLES', default=False,
                   help='build the example programs')
    ctx.add_option('--with-example', action='store',
                   dest='EXAMPLES', default=False,
                   help='example programs to build (comma separated, without .cpp)')
    ctx.add_option('--build-static', action='store_true',
                   dest='BUILD_STATIC', default=False,
                   help='build static library')
    ctx.add_option('--static-dependencies', action='store_true',
                   dest='STATIC_DEPENDENCIES', default=False,
                   help='build with static dependencies from packaging/* dir')
    ctx.add_option('--pkg-config-path', action='store',
                   dest='PKG_CONFIG_PATH', default=False,
                   help='pkg-config path to search for dependencies (default paths will be ignored)')
    ctx.add_option('--with-static-examples', action='store_true',
                   dest='WITH_STATIC_EXAMPLES', default=False,
                   help='build the example programs as static executables; forces --static-dependencies and --static flags')
    ctx.add_option('--with-vamp', action='store_true',
                   dest='WITH_VAMP', default=False,
                   help='build the vamp plugin wrapper')
    ctx.add_option('--with-gaia', action='store_true',
                   dest='WITH_GAIA', default=False,
                   help='build with Gaia support')
    ctx.add_option('--with-tensorflow', action='store_true',
                   dest='WITH_TENSORFLOW', default=False,
                   help='build with Tensorflow support')
    ctx.add_option('--lightweight', action='store',
                   dest='LIGHTWEIGHT', default=False,
                   help='build lightweight version with specified dependencies (comma separated: =' + ','.join(default_libs) + ')')
    ctx.add_option('--ignore-algos', action='store',
                   dest='IGNORE_ALGOS', default=False,
                   help='algorithms to ignore (comma separated)')
    ctx.add_option('--include-algos', action='store',
                   dest='INCLUDE_ALGOS', default=False,
                   help='algorithms to install (comma separated)')
    ctx.add_option('--fft', action='store',
                   dest='FFT', default='FFTW',
                   help='FFT to use - options are \'FFTW\'(default), \'KISS\', and \'ACCELERATE\' framework (Mac Only)')
    ctx.add_option('--only-python', action='store_true',
                   dest='ONLY_PYTHON', default=False,
                   help='build only the python bindings (use a pre-built libessentia)')


def debian_version():
    try:
        v = open('/etc/debian_version').read().strip()
        return [int(n) for n in v.split('.')]
    except IOError:
        return []
    except ValueError:
        # string version instead of numeric
        if 'wheezy' in v or 'sid' in v:
            return [7, 0]
        else:
            return [6, 0]


def configure(ctx):
    if ctx.env.WITH_STATIC_EXAMPLES and not ctx.env.EXAMPLES:
        ctx.env.WITH_EXAMPLES = True

    if ctx.env.LIGHTWEIGHT != False:
        # bool value if --lightweight flag was not specified, string otherwise
        ctx.env.CHECK_LIBS = ['']
        if ctx.env.LIGHTWEIGHT:
            for e in ctx.env.LIGHTWEIGHT.split(","):
                e = e.strip()
                if e not in default_libs:
                    raise ctx.errors.ConfigurationError("Specified dependency [%s] does not exist" % e)
                ctx.env.CHECK_LIBS.append(e)
        ctx.env.CHECK_LIBS = list(set(ctx.env.CHECK_LIBS))
        print("\n=======================Lightweight Mode : Ignoring ALL libraries except %s =======================\n" % ctx.env.CHECK_LIBS)
    else:
        ctx.env.CHECK_LIBS = default_libs

    if ctx.env.WITH_GAIA:
        ctx.env.CHECK_LIBS.append('gaia2')

    if ctx.env.WITH_TENSORFLOW:
        ctx.env.CHECK_LIBS.append('tensorflow')

    if ctx.env.IGNORE_ALGOS:
        for a in ctx.env.IGNORE_ALGOS.split(","):
            a = a.strip()
            ctx.env.ALGOIGNORE.append(a)

    if ctx.env.INCLUDE_ALGOS:
        for a in ctx.env.INCLUDE_ALGOS.split(","):
            a = a.strip()
            ctx.env.ALGOINCLUDE.append(a)

    # overwrite PKG_CONFIG_PATH if it is explicitly specified
    if ctx.env.PKG_CONFIG_PATH:
        os.environ["PKG_CONFIG_PATH"] = ctx.env.PKG_CONFIG_PATH
        os.environ["PKG_CONFIG_LIBDIR"] = os.environ["PKG_CONFIG_PATH"]
        print("→ Searching *.pc pkg-config files for dependencies in %s (default paths are ignored)" % os.environ["PKG_CONFIG_PATH"])

    elif "PKG_CONFIG_PATH" in os.environ:
        print("→ Searching *.pc pkg-config files for dependencies in %s and default paths" % os.environ["PKG_CONFIG_PATH"])

    # Make check_cfg find PKG_CONFIG_PATH
    ctx.env.env = dict(os.environ)
    check_cfg_args = ['--cflags', '--libs']
    #if ctx.env.STATIC_DEPENDENCIES:
    #    check_cfg_args += ['--static']

    if ctx.env.ONLY_PYTHON:
       print("→ Building only Essentia's python bindings (libessentia should be pre-installed)")
       ctx.check_cfg(package='essentia', uselib_store='ESSENTIA',
                      args=check_cfg_args, mandatory=True)
       ctx.env.USE_LIBS = 'ESSENTIA'
       ctx.recurse('python')
       return

    ctx.check_cfg(package=lib_map['EIGEN3'], uselib_store='EIGEN3',
                  args=['eigen3 >= 3.3.4'] + check_cfg_args)

    # Disable Eigen warnings related to meaningless type qualifiers
    # https://gitlab.com/libeigen/eigen/-/issues/115
    ctx.env.DEFINES += ['EIGEN_PERMANENTLY_DISABLE_STUPID_WARNINGS']

    if 'libav' in ctx.env.CHECK_LIBS:
        ctx.check_cfg(package=lib_map['AVCODEC'], uselib_store='AVCODEC',
                      args=['{} >= 55.34.1'.format(lib_map['AVCODEC'])] + check_cfg_args,
                      msg="Checking for '{}' >= 55.34.1".format(lib_map['AVCODEC']),
                      mandatory=False)

        ctx.check_cfg(package=lib_map['AVFORMAT'], uselib_store='AVFORMAT',
                      args=check_cfg_args, mandatory=False)

        ctx.check_cfg(package=lib_map['AVUTIL'], uselib_store='AVUTIL',
                      args=check_cfg_args, mandatory=False)

        ctx.check_cfg(package=lib_map['SWRESAMPLE'], uselib_store='SWRESAMPLE',
                      args=check_cfg_args, mandatory=False)

    if 'libsamplerate' in ctx.env.CHECK_LIBS:
        ctx.check_cfg(package=lib_map['SAMPLERATE'], uselib_store='SAMPLERATE',
                      args=check_cfg_args, mandatory=False)

    if 'taglib' in ctx.env.CHECK_LIBS:
        ctx.check_cfg(package=lib_map['TAGLIB'], uselib_store='TAGLIB',
                      args=['{} >= 1.9'.format(lib_map['TAGLIB'])] + check_cfg_args,
                      msg="Checking for '{}' >= 1.9".format(lib_map['TAGLIB']),
                      mandatory=False)

    if 'yaml' in ctx.env.CHECK_LIBS:
        ctx.check_cfg(package=lib_map['YAML'], uselib_store='YAML',
                      args=check_cfg_args, mandatory=False)
        if not ctx.env.INCLUDES_YAML and sys.platform == 'darwin':
            # an ugly hack for osx, because pkg-config file for yaml-0.1.6 installed by brew
            # is missing include path
            # TODO: file an issue to libyaml brew formula makers?
            ctx.env['INCLUDES_YAML'] = '/'.join(ctx.env['LIBPATH_YAML'][0].split('/')[:-1] + ['include'])
            print(ctx.env['INCLUDES_YAML'])

    if 'fftw' in ctx.env.CHECK_LIBS:
        ctx.check_cfg(package=lib_map['FFTW'], uselib_store='FFTW',
                      args=check_cfg_args, mandatory=False)

    if 'libchromaprint' in ctx.env.CHECK_LIBS:
        ctx.check_cfg(package=lib_map['LIBCHROMAPRINT'], uselib_store='LIBCHROMAPRINT',
                      args=['--cflags', '--libs'], mandatory=False)

    if 'gaia2' in ctx.env.CHECK_LIBS:
        ctx.check_cfg(package=lib_map['GAIA2'], uselib_store='GAIA2',
                      args=check_cfg_args, mandatory=True)

    if 'tensorflow' in ctx.env.CHECK_LIBS:
        ctx.check_cfg(package=lib_map['TENSORFLOW'], uselib_store='TENSORFLOW',
                      args=check_cfg_args, mandatory=True)

    # needed by ffmpeg for the INT64_C macros
    ctx.env.DEFINES += ['__STDC_CONSTANT_MACROS']

    if ctx.env.WITH_EXAMPLES or ctx.env.EXAMPLES or ctx.env.WITH_VAMP:
        ctx.recurse('examples')

    if ctx.env.WITH_PYTHON:
        ctx.recurse('python')


    # prepare the compilation environment using the detected libraries
    print()
    print('================================ CONFIGURATION SUMMARY ================================')

    ctx.env.USE_LIBS = ''

    def has(name):
        return ('HAVE_%s' % name.upper()) in ctx.env['define_key']

    # Select FFT algorithms
    algos = ['FFT']
    if 'ACCELERATE' in ctx.env.FFT:
        print('- using Accelerate Framework for FFT\n')
        ctx.env.LINKFLAGS += ['-framework', 'Accelerate']
        ctx.env.ALGOIGNORE += ['FFTK', 'IFFTK', 'FFTKComplex', 'IFFTKComplex',
                               'FFTW', 'IFFTW', 'FFTWComplex', 'IFFTWComplex']
    elif 'KISS' in ctx.env.FFT:
        print('- using KISS for FFT\n')
        ctx.env.ALGOIGNORE += ['FFTA', 'IFFTA', 'FFTAComplex', 'IFFTAComplex',
                               'FFTW', 'IFFTW', 'FFTWComplex', 'IFFTWComplex']
    else:
        print('- using FFTW for FFT\n')
        if has('fftw'):
            print('- fftw detected!')
            ctx.env.USE_LIBS += ' FFTW'
            ctx.env.ALGOIGNORE += ['FFTK', 'IFFTK', 'FFTKComplex', 'IFFTKComplex',
                                   'FFTA', 'IFFTA', 'FFTAComplex', 'IFFTAComplex']
        else:
            print(' - fftw seems to be missing.')
            print('   The following algorithms will be ignored: %s\n' % algos)
            ctx.env.ALGOIGNORE += ['FFTK', 'IFFTK', 'FFTA', 'IFFTA', 'FFTW', 'IFFTW',
                                   'FFTWComplex', 'IFFTWComplex',
                                   'FFTKComplex', 'IFFTKComplex',
                                   'FFTAComplex', 'IFFTAComplex']
            # TODO what other algorithms dependent on FFT should be also ignored?

            print('   IMPORTANT NOTE: You will encounter compilation errors, because some other algorithms rely on FFT.')
            print('                   To avoid these errors, use alternative FFT libraries (see the --fft flag).\n')

    # TODO Eigen is set as a mandatory dependency as the long-term goal is to
    # use it to replace the outdated TNT code for matrices and linear algebra
    ctx.env.USE_LIBS += ' EIGEN3'

    # this flag guarantees that all the Eigen code that we are including is
    # licensed under MPL2 or more permissive licenses (like BSD)
    # http://eigen.tuxfamily.org/index.php?title=Main_Page#License
    ctx.env.DEFINES += ['EIGEN_MPL2_ONLY']

    # MonoLoader, EqloudLoader, and EasyLoader are dependent on Resample
    algos = [ 'AudioLoader', 'MonoLoader', 'EqloudLoader', 'EasyLoader', 'MonoWriter', 'AudioWriter' ]
    if has('avcodec') and has('avformat') and has('avutil') and has('swresample'):
        print('- FFmpeg / libav detected!')
        ctx.env.USE_LIBS += ' AVFORMAT AVCODEC AVUTIL SWRESAMPLE'

    else:
        print('- FFmpeg (or LibAv on debian/ubuntu) seems to be missing.')
        print('  The following algorithms will be ignored: %s\n' % algos)
        ctx.env.ALGOIGNORE += algos

    algos = ['Resample', 'MonoLoader', 'EqloudLoader', 'EasyLoader']
    if has('samplerate'):
        print('- libsamplerate (SRC) detected!')
        ctx.env.USE_LIBS += ' SAMPLERATE'
    else:
        print('- libsamplerate seems to be missing.')
        print('  The following algorithms will be ignored: %s\n' % algos)
        ctx.env.ALGOIGNORE += algos

    algos = ['AudioLoader', 'MonoLoader', 'EqloudLoader', 'EasyLoader', 'MonoWriter', 'AudioWriter', 'Resample']
    algos_include = list(set(algos) - set(ctx.env.ALGOIGNORE))
    if algos_include:
        print('  The following algorithms will be included: %s\n' % algos_include)
    else:
        print('  Examples requiring FFmpeg / libav and libsamplerate will be ignored\n')

    algos = ['MetadataReader', 'MusicExtractor', 'FreesoundExtractor']
    if has('taglib'):
        print('- TagLib detected!')
        print('  The following algorithms will be included: %s\n' % algos)
        ctx.env.USE_LIBS += ' TAGLIB'
    else:
        print('- TagLib seems to be missing.')
        print('  The following algorithms will be ignored: %s\n' % algos)
        ctx.env.ALGOIGNORE += algos

    algos = ['YamlInput', 'YamlOutput']
    if has('yaml'):
        print('- libyaml detected!')
        print('  The following algorithms will be included: %s\n' % algos)
        ctx.env.USE_LIBS += ' YAML'
    else:
        print('- libyaml seems to be missing.')
        print('  The following algorithms will be ignored: %s\n' % algos)
        ctx.env.ALGOIGNORE += algos

    algos = ['GaiaTransform', 'MusicExtractorSVM']
    if ctx.env.WITH_GAIA:
        if has('gaia2'):
            print('- Gaia2 detected!')
            print('  The following algorithms will be included: %s\n' % algos)
            ctx.env.USE_LIBS += ' GAIA2'
    else:
        print('- Essentia is configured without Gaia2.')
        print('  The following algorithms will be ignored: %s' % algos)
        print('  Examples requiring Gaia2 will be ignored\n')
        ctx.env.ALGOIGNORE += algos

    algos = [ 'Chromaprinter' ]
    if has('libchromaprint'):
        print('- Chromaprint detected!')
        print('  The following algorithms will be included: %s\n' % algos)
        ctx.env.USE_LIBS += ' LIBCHROMAPRINT'
    else:
        print('- Essentia is configured without Chromaprint.')
        print('  The following algorithms will be ignored: %s' % algos)
        ctx.env.ALGOIGNORE += algos

    algos = [ 'TensorflowPredict', 'TensorflowPredictMusiCNN', 'TensorflowPredictVGGish',
              'TensorflowPredictTempoCNN', 'TensorflowPredictCREPE', 'PitchCREPE',
              'TempoCNN', 'TensorflowPredictEffnetDiscogs', 'TensorflowPredict2D',
              'TensorflowPredictFSDSINet', 'TensorflowPredictMAEST',]
    if has('tensorflow'):
        print('- Tensorflow detected!')
        print('  The following algorithms will be included: %s\n' % algos)
        ctx.env.USE_LIBS += ' TENSORFLOW'
    else:
        print('- Essentia is configured without Tensorflow.')
        print('  The following algorithms will be ignored: %s' % algos)
        ctx.env.ALGOIGNORE += algos

    lel = len(ctx.env.EXAMPLE_LIST)
    if lel:
        print('- Compiling %s example%s' % (lel, "" if lel == 1 else "s"))
        print('  %s' % ", ".join(ctx.env.EXAMPLE_LIST))

    algos = buildRegFile(ctx)

    if ctx.env.WITH_PYTHON:
        for a in ['FileOutputProxy', 'FrameCutter']:
            if a not in algos:
                raise ctx.errors.ConfigurationError(
                    "%s algorithm is necessary for python bindings, however it was excluded. "
                    "Please, reconfigure including this algorithm." % a)

    print('\n' + '-' * 87)

    if ctx.env.BUILD_STATIC:
        print('- Building static library')
    else:
        print('- Building shared library')
    if ctx.env.STATIC_DEPENDENCIES:
        print('Static dependencies found in ' + os.environ["PKG_CONFIG_PATH"] + ' will be used for:')
    if ctx.env.WITH_PYTHON:
        print('- Building Python extension')
    if ctx.env.WITH_STATIC_EXAMPLES:
        print('- Building static examples')
    elif ctx.env.WITH_EXAMPLES:
        print('- Building examples')
    if ctx.env.WITH_VAMP:
        print('- Building Vamp plugin')

    print('=======================================================================================')


    libs = ctx.env.USE_LIBS.strip().split(' ')

    # Prepare pkg-config file
    if ctx.env.BUILD_STATIC:
        # For the static library, find all -l flags we'll need
        lflags = [l for lib in libs for l in ctx.env["LIB_" + lib]]
        lflags = ' '.join(['-l%s' % lib for lib in lflags])
        lpaths = [l for lib in libs for l in ctx.env["LIBPATH_" + lib]]
        lpaths = ' '.join(['-L%s' % lib for lib in set(lpaths)])
    else:
        lflags = lpaths = ''

    # Prepare pkg-config .pc file variables
    requires = ' '.join([lib_map[l] for l in libs])
    prefix = os.path.normpath(ctx.options.prefix)
    ctx.env.pcfile_opts = {'PREFIX': prefix,
                           'VERSION': ctx.env.VERSION,
                           'REQUIRESPRIVATE': requires,
                           'LFLAGS': lflags,
                           'LPATHS': lpaths
                           }

from waflib.Task import Task
class BuildAlgoReg(Task):
    def run(self):
        return self.exec_command('cp %s %s' % (self.inputs[0].abspath(),
                                               self.outputs[0].abspath()))


def buildRegFile(ctx):
    # get list of available algorithms
    from utils.algorithms_info import get_all_algorithms, create_registration_cpp, create_version_h

    algos = get_all_algorithms(ctx.path.find_dir('algorithms').abspath(),
                               root_dir = ctx.path.abspath())

    # select the algorithms we want to build
    if ctx.env['ALGOINCLUDE']:
        algos_included = {}
        algos_not_found = []
        # hack to automatically include the detected version of FFT when FFT is included
        fft_algos = ['FFTK', 'IFFTK', 'FFTA', 'IFFTA', 'FFTW', 'IFFTW']
        for alg in ctx.env['ALGOINCLUDE']:
            if alg not in algos.keys() and alg != 'FFT':
                algos_not_found.append(alg)
                continue
            if alg == 'FFT':
                selected_ffts = [alg for alg in fft_algos if alg not in ctx.env.ALGOIGNORE]
                for fft_alg in selected_ffts:
                    algos_included[fft_alg] = algos[fft_alg]
                continue
            algos_included[alg] = algos[alg]
        algos = algos_included
        if algos_not_found:
            print('Warning: the following algorithms could not be found: %s' % ', '.join(algos_not_found))
        print('Building the following algorithms: %s' % ', '.join(algos.keys()))
    else:
        print('Building all the algorithms')

    if ctx.env['ALGOIGNORE']:
        ctx.env['ALGOIGNORE'] = list(set(ctx.env['ALGOIGNORE']))
        algos_ignored = []
        for alg in ctx.env['ALGOIGNORE']:
            if alg in algos.keys():
                algos_ignored.append(alg)
        if algos_ignored:
            print('Ignoring the following algorithms: %s' % ', '.join(algos_ignored))
            for algoname in algos_ignored:
                del algos[algoname]

    # create version.h header file
    create_version_h('src/version.h', ctx.env.VERSION, ctx.env.GIT_SHA)

    # create algorithms registration file
    algoreg_path = 'src/algorithms/essentia_algorithms_reg.cpp'
    create_registration_cpp(algos, algoreg_path, use_streaming=True)

    print('Created algorithms registration file')
    return algos


def build(ctx):
    print('→ building from ' + ctx.path.abspath())

    if ctx.env.ONLY_PYTHON:
        ctx.recurse('python')
        return

    #print('  BUILD ENV:\n%s' % ctx.env)

    # add essentia root folder to path to be able to import utils.algorithms_info
    sys.path = [ctx.path.find_dir('..')] + sys.path

    algos = buildRegFile(ctx)

    sources = ctx.path.ant_glob('essentia/**/*.cpp')

    # do not compile audiocontext.cpp if we're compiling without libav
    if 'AVCODEC' not in ctx.env.USE_LIBS:
        sources = [ s for s in sources if 'audiocontext' not in str(s) ]

    # do not compile anything with yaml if we are compiling without libyaml
    if 'YAML' not in ctx.env.USE_LIBS:
        sources = [ s for s in sources if 'yaml' not in str(s) ]
        sources = [ s for s in sources if 'jsonconvert' not in str(s) ]

    # add all algorithms found in the algorithms/ folder
    sources += [ ctx.path.find_resource('algorithms/essentia_algorithms_reg.cpp') ]
    sources += [ ctx.path.find_resource(algo['source']) for algo in algos.values() ]

    # TODO: recursive includes are needed only for the algorithms, not for the base
    #       library. See if there's no way to split them.
    ctx.env.INCLUDES = [ '.', 'essentia', 'essentia/scheduler', 'essentia/streaming',
                         'essentia/streaming/algorithms', 'essentia/utils',
                         '3rdparty']

    # do not compile splineutil.cpp if we are not compiling Spline and CubicSpline
    if 'Spline' not in ctx.env.ALGOIGNORE or 'CubicSpline' not in ctx.env.ALGOIGNORE:
        ctx.env.INCLUDES += ['3rdparty/spline' ]
        sources += [ ctx.path.find_resource('3rdparty/spline/splineutil.cpp') ]
    else:
        print ('Building without 3rdparty spline library code because Spline and CubicSpline algorithms are ignored')

    # do not compile nnls.h if we are not compiling NNLSChroma
    if 'NNLSChroma' not in ctx.env.ALGOIGNORE:
        ctx.env.INCLUDES += ['3rdparty/nnls' ]
        sources += [ ctx.path.find_resource('3rdparty/nnls/nnls.c') ]
    else:
        print ('Building without 3rdparty nnls library code because NNLSChroma algorithms are ignored')

    # Add Kiss Dependancy stuff
    if 'KISS' in ctx.env.FFT:
        ctx.env.INCLUDES += ['3rdparty/kiss_fft130' ]
        sources += [ ctx.path.find_resource('3rdparty/kiss_fft130/kiss_fft.c') ]
        sources += [ ctx.path.find_resource('3rdparty/kiss_fft130/tools/kiss_fftr.c') ]

    # Add Chromaprint Dependancy stuff 
    """
    if 'CHROMAPRINT' not in ctx.env.ALGOIGNORE:
        ctx.env.INCLUDES += ['3rdparty/chromaprint-1.4.2/src' ]
        sources += [ ctx.path.find_resource('3rdparty/chromaprint-1.4.2/src/chromaprint.cpp') ]

        sources += [ ctx.path.find_resource('3rdparty/chromaprint-1.4.2/src/fingerprint_compressor.cpp') ]
        sources += [ ctx.path.find_resource('3rdparty/chromaprint-1.4.2/src/fingerprint_decompressor.cpp') ]
        sources += [ ctx.path.find_resource('3rdparty/chromaprint-1.4.2/src/fingerprint_matcher.cpp') ]
        sources += [ ctx.path.find_resource('3rdparty/chromaprint-1.4.2/src/fingerprinter_configuration.cpp') ]
        sources += [ ctx.path.find_resource('3rdparty/chromaprint-1.4.2/src/fingerprinter_configuration.cpp') ]
        sources += [ ctx.path.find_resource('3rdparty/chromaprint-1.4.2/src/simhash.cpp') ]
    """

    # do not compile Cephes functions if we are not compiling SNR
    if 'SNR' not in ctx.env.ALGOIGNORE:
        ctx.env.INCLUDES += ['3rdparty/cephes/bessel/' ]
        sources += ctx.path.ant_glob('3rdparty/cephes/bessel/*.cpp')
    else:
        print('Building without 3rdparty Cephes library code (Bessel functions) because SNR algorithm is ignored')

    if ctx.env.BUILD_STATIC:
        ctx.stlib(
            source   = sources,
            target   = 'essentia',
            use      = ctx.env.USE_LIBS,
            install_path = '${PREFIX}/lib',
            #includes = ctx.env.includes
        )
    else:
        ctx.shlib(
            source   = sources,
            target   = 'essentia',
            use      = ctx.env.USE_LIBS,
            includes = ctx.env.INCLUDES,
            cxxflags = [ '-w' ],
            install_path = '${PREFIX}/lib'
        )

    ctx(source='../essentia.pc.in', **ctx.env.pcfile_opts)

    ctx.add_group()


    # install headers if asked to
    headers = ctx.path.ant_glob('essentia/**/*.h')
    for h in headers:
        install_dir = os.path.split(h.srcpath())[0][4:]
        ctx.install_files('${PREFIX}/include/' + install_dir, h)
    # version.h
    ctx.install_files('${PREFIX}/include/essentia', 'version.h')

    # install pkgconfig file
    #pc = ctx.path.ant_glob('essentia/build/essentia.pc') #TODO remove
    #ctx.install_files('${PREFIX}/lib/pkgconfig', pc)     #TODO remove
    ctx.install_files('${PREFIX}/lib/pkgconfig', '../build/essentia.pc')


    if ctx.env.EXAMPLE_LIST or ctx.env.WITH_VAMP:
        ctx.recurse('examples')

    if ctx.env.WITH_PYTHON:
        ctx.recurse('python')
