Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

static link TA-LIB on Linux #628

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ docs/.tadoc.org.html
*.pyc
build/
dist/
c-ta-lib/
*.so
.*
*~
Expand Down
15 changes: 15 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
14 changes: 13 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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)
]

Expand Down
6 changes: 3 additions & 3 deletions talib/_func.pxi
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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 = <double*>outreal.data
for i from 0 <= i < min(lookback, length):
outreal_data[i] = NaN
Expand All @@ -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 = <int*>outinteger.data
for i from 0 <= i < min(lookback, length):
outinteger_data[i] = 0
Expand Down
6 changes: 3 additions & 3 deletions tools/generate_func.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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 = <double*>outreal.data
for i from 0 <= i < min(lookback, length):
outreal_data[i] = NaN
Expand All @@ -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 = <int*>outinteger.data
for i from 0 <= i < min(lookback, length):
outinteger_data[i] = 0
Expand Down