diff --git a/.gitignore b/.gitignore index 49ddb78e1..539c1abc2 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ docs/.tadoc.org.html *.pyc build/ dist/ +c-ta-lib/ *.so .* *~ diff --git a/Makefile b/Makefile index 7717a7fce..e339e537b 100644 --- a/Makefile +++ b/Makefile @@ -3,9 +3,15 @@ build: python3 setup.py build_ext --inplace +build_static: + TA_LINK_STATIC=1 TA_INCLUDE_PATH=c-ta-lib/include TA_LIBRARY_PATH=c-ta-lib/lib python3 setup.py build_ext --inplace + install: python3 setup.py install +install_static: + TA_LINK_STATIC=1 TA_INCLUDE_PATH=c-ta-lib/include TA_LIBRARY_PATH=c-ta-lib/lib python3 setup.py install + talib/_func.pxi: tools/generate_func.py python3 tools/generate_func.py > talib/_func.pxi @@ -28,3 +34,12 @@ test: build sdist: python3 setup.py sdist --formats=gztar,zip + +sdist_static: + TA_LINK_STATIC=1 TA_INCLUDE_PATH=c-ta-lib/include TA_LIBRARY_PATH=c-ta-lib/lib python3 setup.py sdist --formats=gztar,zip + +talib_static: + tools/build_talib_from_source.bash ${PWD}/c-ta-lib + +wheel_static: + TA_LINK_STATIC=1 TA_INCLUDE_PATH=c-ta-lib/include TA_LIBRARY_PATH=c-ta-lib/lib python3 setup.py bdist_wheel diff --git a/README.md b/README.md index 67f42fcb6..f5e5892ef 100644 --- a/README.md +++ b/README.md @@ -130,6 +130,17 @@ $ sudo make install Note: if your directory path includes spaces, the installation will probably fail with ``No such file or directory`` errors. +###### Link static ta-lib in Linux + +Linux build can link `ta-lib` static, so there is no need to install `ta-lib` global, may be easier to distribute. + +1. build `ta-lib` to current dir, `make talib_static`, it download`ta-lib` and build it to `c-ta-lib` of current dir. +2. install static link version of ta-lib-python, `make install_static` + +A bool environment variables `TA_LINK_STATIC` is used to tell `setup.py` do static link `ta-lib`, it find `libta_lib.a` +in all `library_dirs`, when found, it set `lib_talib_name` with empty str to disable dynamic link. + + ### Troubleshooting If you get a warning that looks like this: diff --git a/setup.py b/setup.py index 8bacdff5f..c3a33ecef 100644 --- a/setup.py +++ b/setup.py @@ -19,6 +19,7 @@ requires = {"requires": ["numpy"]} lib_talib_name = 'ta_lib' # the underlying C library's name +lib_talib_static_lib = '' # static C library, such as '/usr/lib/libta_lib.a' platform_supported = False @@ -55,6 +56,15 @@ if 'TA_LIBRARY_PATH' in os.environ: library_dirs = os.environ['TA_LIBRARY_PATH'].split(os.pathsep) +if 'TA_LINK_STATIC' in os.environ: + for base in library_dirs: + fname = f'{base}/libta_lib.a' + if os.path.exists(fname): + lib_talib_static_lib = fname + lib_talib_name = '' + break + + if not platform_supported: raise NotImplementedError(sys.platform) @@ -130,9 +140,11 @@ def build_extensions(self): Extension( 'talib._ta_lib', ['talib/_ta_lib.pyx' if has_cython else 'talib/_ta_lib.c'], + #define_macros=[('NPY_NO_DEPRECATED_API', 'NPY_1_7_API_VERSION')], include_dirs=include_dirs, library_dirs=library_dirs, - libraries=[lib_talib_name], + libraries=[lib_talib_name] if len(lib_talib_name) > 0 else [], + extra_objects=[lib_talib_static_lib] if len(lib_talib_static_lib) > 0 else [], runtime_library_dirs=[] if sys.platform == 'win32' else library_dirs) ] diff --git a/talib/_func.pxi b/talib/_func.pxi index 5d60d7dd3..e3485b9e5 100644 --- a/talib/_func.pxi +++ b/talib/_func.pxi @@ -22,7 +22,7 @@ cdef np.ndarray check_array(np.ndarray real): raise Exception("input array type is not double") if real.ndim != 1: raise Exception("input array has wrong dimensions") - if not (PyArray_FLAGS(real) & np.NPY_C_CONTIGUOUS): + if not (PyArray_FLAGS(real) & np.NPY_ARRAY_C_CONTIGUOUS): real = PyArray_GETCONTIGUOUS(real) return real @@ -122,7 +122,7 @@ cdef np.ndarray make_double_array(np.npy_intp length, int lookback): cdef: np.ndarray outreal double* outreal_data - outreal = PyArray_EMPTY(1, &length, np.NPY_DOUBLE, np.NPY_DEFAULT) + outreal = PyArray_EMPTY(1, &length, np.NPY_DOUBLE, 0) outreal_data = outreal.data for i from 0 <= i < min(lookback, length): outreal_data[i] = NaN @@ -132,7 +132,7 @@ cdef np.ndarray make_int_array(np.npy_intp length, int lookback): cdef: np.ndarray outinteger int* outinteger_data - outinteger = PyArray_EMPTY(1, &length, np.NPY_INT32, np.NPY_DEFAULT) + outinteger = PyArray_EMPTY(1, &length, np.NPY_INT32, 0) outinteger_data = outinteger.data for i from 0 <= i < min(lookback, length): outinteger_data[i] = 0 diff --git a/tools/generate_func.py b/tools/generate_func.py index 5a625ef08..3a8b34198 100644 --- a/tools/generate_func.py +++ b/tools/generate_func.py @@ -73,7 +73,7 @@ raise Exception("input array type is not double") if real.ndim != 1: raise Exception("input array has wrong dimensions") - if not (PyArray_FLAGS(real) & np.NPY_C_CONTIGUOUS): + if not (PyArray_FLAGS(real) & np.NPY_ARRAY_C_CONTIGUOUS): real = PyArray_GETCONTIGUOUS(real) return real @@ -173,7 +173,7 @@ cdef: np.ndarray outreal double* outreal_data - outreal = PyArray_EMPTY(1, &length, np.NPY_DOUBLE, np.NPY_DEFAULT) + outreal = PyArray_EMPTY(1, &length, np.NPY_DOUBLE, 0) outreal_data = outreal.data for i from 0 <= i < min(lookback, length): outreal_data[i] = NaN @@ -183,7 +183,7 @@ cdef: np.ndarray outinteger int* outinteger_data - outinteger = PyArray_EMPTY(1, &length, np.NPY_INT32, np.NPY_DEFAULT) + outinteger = PyArray_EMPTY(1, &length, np.NPY_INT32, 0) outinteger_data = outinteger.data for i from 0 <= i < min(lookback, length): outinteger_data[i] = 0