From 84fe61275c52c08e15cf1ed4d507d7c25ee5420d Mon Sep 17 00:00:00 2001 From: mckelvin Date: Sun, 5 Feb 2017 13:43:47 +0800 Subject: [PATCH] Build from source if the ta-lib is not installed --- .travis.yml | 1 + MANIFEST.in | 13 ++++++ setup.py | 91 ++++++++++++++++++++++++++++++---------- talib/_ta_lib.c | 12 ++---- talib/_ta_lib.pxd | 8 ++-- tools/generate_func.py | 9 ++-- tools/generate_stream.py | 9 ++-- 7 files changed, 102 insertions(+), 41 deletions(-) create mode 100644 MANIFEST.in diff --git a/.travis.yml b/.travis.yml index 6695f589d..dc13122b8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,6 +15,7 @@ env: TA_INCLUDE_PATH=$DEPS_DIR/include LD_LIBRARY_PATH=$DEPS_DIR/lib TA_LIBRARY_PATH=$DEPS_DIR/lib + - WITH_TA_LIBRARY=no cache: directories: - $DEPS_DIR diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 000000000..6173c51f7 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,13 @@ +include README.md +include AUTHORS +include CHANGELOG +include COPYRIGHT +include DEVELOPMENT +include LICENSE +include requirements.txt +recursive-include vendor * +recursive-include talib *.py *.pyx *.pxi *.pxd *.c +prune vendor/ta-lib/temp +prune vendor/ta-lib/make +prune vendor/ta-lib/ide +prune vendor/ta-lib/src/tools diff --git a/setup.py b/setup.py index fc10846db..649438b13 100644 --- a/setup.py +++ b/setup.py @@ -1,5 +1,6 @@ #!/usr/bin/env python +import glob import sys import os import warnings @@ -21,19 +22,22 @@ from distutils.extension import Extension lib_talib_name = 'ta_lib' # the underlying C library's name +sources = [] platform_supported = False for prefix in ['darwin', 'linux', 'bsd', 'sunos']: if prefix in sys.platform: platform_supported = True include_dirs = [ - '/usr/include', - '/usr/local/include', - '/opt/include', - '/opt/local/include', + '/usr/include/ta-lib', + '/usr/local/include/ta-lib', + '/opt/include/ta-lib', + '/opt/local/include/ta-lib', ] if 'TA_INCLUDE_PATH' in os.environ: - include_dirs.append(os.environ['TA_INCLUDE_PATH']) + include_dirs.append( + os.path.join(os.environ['TA_INCLUDE_PATH'], "ta-lib") + ) lib_talib_dirs = [ '/usr/lib', '/usr/local/lib', @@ -49,7 +53,7 @@ if sys.platform == "win32": platform_supported = True lib_talib_name = 'ta_libc_cdr' - include_dirs = [r"c:\ta-lib\c\include"] + include_dirs = [r"c:\ta-lib\c\include\ta-lib"] lib_talib_dirs = [r"c:\ta-lib\c\lib"] if not platform_supported: @@ -66,6 +70,7 @@ except ImportError: has_cython = False +libraries = [lib_talib_name] for lib_talib_dir in lib_talib_dirs: try: files = os.listdir(lib_talib_dir) @@ -74,7 +79,51 @@ except OSError: pass else: - warnings.warn('Cannot find ta-lib library, installation may fail.') + libraries = [] + warnings.warn( + 'Cannot find ta-lib library, will try to build from source.' + ) + # find vendor/ta-lib -name "*.h" -exec dirname {} \; | sort | uniq + vendor_dir = os.path.join( + os.path.dirname(os.path.abspath(__file__)), + "vendor", + ) + vendor_talib_dir = os.path.join( + vendor_dir, + "ta-lib", + ) + talib_include_dirs = [ + ("include", ), + ("src", "ta_abstract"), + ("src", "ta_abstract", "frames"), + ("src", "ta_common"), + ("src", "ta_func"), + ] + include_dirs.extend(( + os.path.join(vendor_talib_dir, *path_args) + for path_args in talib_include_dirs + )) + + talib_source_dirs = [ + ("ta_abstract", ), + ("ta_abstract", "frames"), + ("ta_abstract", "tables"), + ("ta_common", ), + ("ta_func", ) + ] + for path_args in talib_source_dirs: + source_dir = os.path.join(vendor_talib_dir, "src", *path_args) + sources.extend(glob.glob(os.path.join(source_dir, "*.c"))) + excel_glue_c_file = os.path.join( + vendor_talib_dir, "src", "ta_abstract", "excel_glue.c" + ) + try: + sources.remove(excel_glue_c_file) + except ValueError: + pass + libraries = [] + lib_talib_dirs = [] + cmdclass = {} if has_cython: @@ -83,22 +132,22 @@ ext_modules = [ Extension( 'talib._ta_lib', - ['talib/_ta_lib.pyx' if has_cython else 'talib/_ta_lib.c'], + ['talib/_ta_lib.pyx' if has_cython else 'talib/_ta_lib.c'] + sources, include_dirs=include_dirs, library_dirs=lib_talib_dirs, - libraries=[lib_talib_name] + libraries=libraries ) ] setup( - name = 'TA-Lib', - version = '0.4.10', - description = 'Python wrapper for TA-Lib', - author = 'John Benediktsson', - author_email = 'mrjbq7@gmail.com', - url = 'http://github.com/mrjbq7/ta-lib', - download_url = 'https://github.com/mrjbq7/ta-lib/releases', - classifiers = [ + name='TA-Lib', + version='0.4.10', + description='Python wrapper for TA-Lib', + author='John Benediktsson', + author_email='mrjbq7@gmail.com', + url='http://github.com/mrjbq7/ta-lib', + download_url='https://github.com/mrjbq7/ta-lib/releases', + classifiers=[ "License :: OSI Approved :: BSD License", "Development Status :: 4 - Beta", "Operating System :: Unix", @@ -117,8 +166,8 @@ "Intended Audience :: Science/Research", "Intended Audience :: Financial and Insurance Industry", ], - packages = ['talib'], - ext_modules = ext_modules, - cmdclass = cmdclass, - requires = ['numpy'], + packages=['talib'], + ext_modules=ext_modules, + cmdclass=cmdclass, + requires=['numpy'], ) diff --git a/talib/_ta_lib.c b/talib/_ta_lib.c index 86bddd801..9bbc105b5 100644 --- a/talib/_ta_lib.c +++ b/talib/_ta_lib.c @@ -429,14 +429,10 @@ static CYTHON_INLINE float __PYX_NAN() { #define __PYX_HAVE__talib___ta_lib #define __PYX_HAVE_API__talib___ta_lib -#if defined(WIN32) || defined(MS_WINDOWS) -#include "ta-libc.h" -#else -#include "ta-lib/ta_defs.h" -#include "ta-lib/ta_common.h" -#include "ta-lib/ta_abstract.h" -#include "ta-lib/ta_func.h" -#endif +#include "ta_defs.h" +#include "ta_common.h" +#include "ta_abstract.h" +#include "ta_func.h" #include #include #include diff --git a/talib/_ta_lib.pxd b/talib/_ta_lib.pxd index 60d43a309..346bd6fa5 100644 --- a/talib/_ta_lib.pxd +++ b/talib/_ta_lib.pxd @@ -1,5 +1,5 @@ -cdef extern from "ta-lib/ta_defs.h": +cdef extern from "ta_defs.h": ctypedef int TA_RetCode ctypedef int TA_RetCode @@ -84,7 +84,7 @@ cdef extern from "ta-lib/ta_defs.h": TA_CandleSettingType TA_Equal = 10 TA_CandleSettingType TA_AllCandleSettings = 11 -cdef extern from "ta-lib/ta_common.h": +cdef extern from "ta_common.h": char *TA_GetVersionString() char *TA_GetVersionMajor() char *TA_GetVersionMinor() @@ -109,7 +109,7 @@ cdef extern from "ta-lib/ta_common.h": TA_RetCode TA_Initialize() TA_RetCode TA_Shutdown() -cdef extern from "ta-lib/ta_abstract.h": +cdef extern from "ta_abstract.h": TA_RetCode TA_GroupTableAlloc(TA_StringTable **table) TA_RetCode TA_GroupTableFree(TA_StringTable *table) @@ -192,7 +192,7 @@ cdef extern from "ta-lib/ta_abstract.h": char* TA_FunctionDescriptionXML() -cdef extern from "ta-lib/ta_func.h": +cdef extern from "ta_func.h": TA_RetCode TA_ACOS(int startIdx, int endIdx, const double inReal[], int *outBegIdx, int *outNBElement, double outReal[]) int TA_ACOS_Lookback() TA_RetCode TA_AD(int startIdx, int endIdx, const double inHigh[], const double inLow[], const double inClose[], const double inVolume[], int *outBegIdx, int *outNBElement, double outReal[]) diff --git a/tools/generate_func.py b/tools/generate_func.py index 61cc82896..b98294c3b 100644 --- a/tools/generate_func.py +++ b/tools/generate_func.py @@ -11,17 +11,18 @@ # FIXME: don't return number of elements since it always equals allocation? functions = [] -include_paths = ['/usr/include', '/usr/local/include', '/opt/include', '/opt/local/include'] +include_paths = ['/usr/include/ta-lib', '/usr/local/include/ta-lib', '/opt/include/ta-lib', '/opt/local/include/ta-lib'] if sys.platform == 'win32': - include_paths = [r'c:\ta-lib\c\include'] + include_paths = [r'c:\ta-lib\c\include\ta-lib'] +include_paths.append(os.path.join(os.path.dirname(os.path.dirname(__file__)), "vendor", "ta-lib", "include")) header_found = False for path in include_paths: - ta_func_header = os.path.join(path, 'ta-lib', 'ta_func.h') + ta_func_header = os.path.join(path, 'ta_func.h') if os.path.exists(ta_func_header): header_found = True break if not header_found: - print('Error: ta-lib/ta_func.h not found', file=sys.stderr) + print('Error: ta_func.h not found', file=sys.stderr) sys.exit(1) with open(ta_func_header) as f: tmp = [] diff --git a/tools/generate_stream.py b/tools/generate_stream.py index 48df55b6f..8e7b25216 100644 --- a/tools/generate_stream.py +++ b/tools/generate_stream.py @@ -11,17 +11,18 @@ # FIXME: don't return number of elements since it always equals allocation? functions = [] -include_paths = ['/usr/include', '/usr/local/include', '/opt/include', '/opt/local/include'] +include_paths = ['/usr/include/ta-lib', '/usr/local/include/ta-lib', '/opt/include/ta-lib', '/opt/local/include/ta-lib'] if sys.platform == 'win32': - include_paths = [r'c:\ta-lib\c\include'] + include_paths = [r'c:\ta-lib\c\include\ta-lib'] +include_paths.append(os.path.join(os.path.dirname(os.path.dirname(__file__)), "vendor", "ta-lib", "include")) header_found = False for path in include_paths: - ta_func_header = os.path.join(path, 'ta-lib', 'ta_func.h') + ta_func_header = os.path.join(path, 'ta_func.h') if os.path.exists(ta_func_header): header_found = True break if not header_found: - print('Error: ta-lib/ta_func.h not found', file=sys.stderr) + print('Error: ta_func.h not found', file=sys.stderr) sys.exit(1) with open(ta_func_header) as f: tmp = []