The setup script now attempts to build the _aubio extension as follows: - if src/aubio.h is found, use it to generate python/gen/ files - if build/src/ is found, use it to link python-aubio against libaubio - otherwise: - add all libaubio source (src/*) to the python module sources - look for optional dependencies using pkg-config - set flags accordingly - otherwise, look for aubio headers and libraries using pkg-config This should help building the python module in a virtualenv (#2), on windows (#55), and allow installing aubio directly with pip.
Showing the changes to python (1 of 2 files). Show all
Unified · Split
| @@ -1,6 +1,114 @@ | |||
| 1 | """ A collection of function used from setup.py distutils script """ | ||
| 2 | # | ||
| 3 | import sys, os, glob, subprocess | ||
| 1 | import distutils, distutils.command.clean, distutils.dir_util | 4 | import distutils, distutils.command.clean, distutils.dir_util |
| 2 | from .gen_external import generate_external, header, output_path | 5 | from .gen_external import generate_external, header, output_path |
| 3 | 6 | ||
| 7 | # inspired from https://gist.github.com/abergmeier/9488990 | ||
| 8 | def add_packages(packages, ext=None, **kw): | ||
| 9 | """ use pkg-config to search which of 'packages' are installed """ | ||
| 10 | flag_map = { | ||
| 11 | '-I': 'include_dirs', | ||
| 12 | '-L': 'library_dirs', | ||
| 13 | '-l': 'libraries'} | ||
| 14 | |||
| 15 | # if a setuptools extension is passed, fill it with pkg-config results | ||
| 16 | if ext: | ||
| 17 | kw = {'include_dirs': ext.include_dirs, | ||
| 18 | 'extra_link_args': ext.extra_link_args, | ||
| 19 | 'library_dirs': ext.library_dirs, | ||
| 20 | 'libraries': ext.libraries, | ||
| 21 | } | ||
| 22 | |||
| 23 | for package in packages: | ||
| 24 | try: | ||
| 25 | cmd = ['pkg-config', '--libs', '--cflags', package] | ||
| 26 | tokens = subprocess.check_output(cmd) | ||
| 27 | except subprocess.CalledProcessError: | ||
| 28 | print("{:s} could not be found".format(package)) | ||
| 29 | continue | ||
| 30 | tokens = tokens.decode('utf8').split() | ||
| 31 | for token in tokens: | ||
| 32 | key = token[:2] | ||
| 33 | try: | ||
| 34 | arg = flag_map[key] | ||
| 35 | value = token[2:] | ||
| 36 | except KeyError: | ||
| 37 | arg = 'extra_link_args' | ||
| 38 | value = token | ||
| 39 | kw.setdefault(arg, []).append(value) | ||
| 40 | for key, value in iter(kw.items()): # remove duplicated | ||
| 41 | kw[key] = list(set(value)) | ||
| 42 | return kw | ||
| 43 | |||
| 44 | def add_local_aubio_header(ext): | ||
| 45 | """ use local "src/aubio.h", not <aubio/aubio.h>""" | ||
| 46 | ext.define_macros += [('USE_LOCAL_AUBIO', 1)] | ||
| 47 | ext.include_dirs += ['src'] # aubio.h | ||
| 48 | |||
| 49 | def add_local_aubio_lib(ext): | ||
| 50 | """ add locally built libaubio from build/src """ | ||
| 51 | print("Info: using locally built libaubio") | ||
| 52 | ext.library_dirs += [os.path.join('build', 'src')] | ||
| 53 | ext.libraries += ['aubio'] | ||
| 54 | |||
| 55 | def add_local_aubio_sources(ext): | ||
| 56 | """ build aubio inside python module instead of linking against libaubio """ | ||
| 57 | print("Warning: libaubio was not built with waf, adding src/") | ||
| 58 | # create an empty header, macros will be passed on the command line | ||
| 59 | fake_config_header = os.path.join('python', 'ext', 'config.h') | ||
| 60 | distutils.file_util.write_file(fake_config_header, "") | ||
| 61 | aubio_sources = glob.glob(os.path.join('src', '**.c')) | ||
| 62 | aubio_sources += glob.glob(os.path.join('src', '*', '**.c')) | ||
| 63 | ext.sources += aubio_sources | ||
| 64 | # define macros (waf puts them in build/src/config.h) | ||
| 65 | for define_macro in ['HAVE_STDLIB_H', 'HAVE_STDIO_H', | ||
| 66 | 'HAVE_MATH_H', 'HAVE_STRING_H', | ||
| 67 | 'HAVE_LIMITS_H', 'HAVE_MEMCPY_HACKS']: | ||
| 68 | ext.define_macros += [(define_macro, 1)] | ||
| 69 | |||
| 70 | # loof for additional packages | ||
| 71 | print("Info: looking for *optional* additional packages") | ||
| 72 | packages = ['libavcodec', 'libavformat', 'libavutil', 'libavresample', | ||
| 73 | 'jack', | ||
| 74 | 'sndfile', 'samplerate', | ||
| 75 | #'fftw3f', | ||
| 76 | ] | ||
| 77 | add_packages(packages, ext=ext) | ||
| 78 | if 'avcodec' in ext.libraries \ | ||
| 79 | and 'avformat' in ext.libraries \ | ||
| 80 | and 'avutil' in ext.libraries \ | ||
| 81 | and 'avresample' in ext.libraries: | ||
| 82 | ext.define_macros += [('HAVE_LIBAV', 1)] | ||
| 83 | if 'jack' in ext.libraries: | ||
| 84 | ext.define_macros += [('HAVE_JACK', 1)] | ||
| 85 | if 'sndfile' in ext.libraries: | ||
| 86 | ext.define_macros += [('HAVE_SNDFILE', 1)] | ||
| 87 | if 'samplerate' in ext.libraries: | ||
| 88 | ext.define_macros += [('HAVE_SAMPLERATE', 1)] | ||
| 89 | if 'fftw3f' in ext.libraries: | ||
| 90 | ext.define_macros += [('HAVE_FFTW3F', 1)] | ||
| 91 | ext.define_macros += [('HAVE_FFTW3', 1)] | ||
| 92 | |||
| 93 | # add accelerate on darwin | ||
| 94 | if sys.platform.startswith('darwin'): | ||
| 95 | ext.extra_link_args += ['-framework', 'accelerate'] | ||
| 96 | ext.define_macros += [('HAVE_ACCELERATE', 1)] | ||
| 97 | |||
| 98 | ext.define_macros += [('HAVE_WAVWRITE', 1)] | ||
| 99 | ext.define_macros += [('HAVE_WAVREAD', 1)] | ||
| 100 | # TODO: | ||
| 101 | # add cblas | ||
| 102 | if 0: | ||
| 103 | ext.libraries += ['cblas'] | ||
| 104 | ext.define_macros += [('HAVE_ATLAS_CBLAS_H', 1)] | ||
| 105 | |||
| 106 | def add_system_aubio(ext): | ||
| 107 | # use pkg-config to find aubio's location | ||
| 108 | add_packages(['aubio'], ext) | ||
| 109 | if 'aubio' not in ext.libraries: | ||
| 110 | print("Error: libaubio not found") | ||
| 111 | |||
| 4 | class CleanGenerated(distutils.command.clean.clean): | 112 | class CleanGenerated(distutils.command.clean.clean): |
| 5 | def run(self): | 113 | def run(self): |
| 6 | distutils.dir_util.remove_tree(output_path) | 114 | distutils.dir_util.remove_tree(output_path) |
| @@ -24,4 +132,4 @@ class GenerateCommand(distutils.cmd.Command): · 17 unmodified lines | |||
| 24 | 132 | ||
| 25 | def run(self): | 133 | def run(self): |
| 26 | self.announce( 'Generating code', level=distutils.log.INFO) | 134 | self.announce( 'Generating code', level=distutils.log.INFO) |
| 27 | generated_object_files = generate_external(header, output_path, usedouble = self.enable_double) | 135 | generated_object_files = generate_external(header, output_path, usedouble=self.enable_double) |