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

How do you build kaldi/lib/_clif.so? #72

Closed
dmitriy-serdyuk opened this issue Dec 30, 2018 · 21 comments
Closed

How do you build kaldi/lib/_clif.so? #72

dmitriy-serdyuk opened this issue Dec 30, 2018 · 21 comments

Comments

@dmitriy-serdyuk
Copy link

I am trying to build a wheel for this package. I managed to encapsulate kaldi shared lib into the wheel using auditwheel. Unfortunately it still fails with

    from ._kaldi_error import *
ImportError: _clif.so: cannot open shared object file: No such file or directory

I don't understand how you build kaldi/lib/_clif.so from sources in pykaldi/kaldi/lib/clif/python/. Is there some code missing in the repo?

@dogancan
Copy link
Member

dogancan commented Dec 30, 2018

The cmake incantation for buildingkaldi/lib/_clif.so is here.

How are you building pykaldi? Aren't you using cmake like we do?

It seems like you are building the clif shared library and linking against it but the python modules cannot find it at run time, since you are getting an import error instead of a linker error. We set the RPATH of pykaldi modules here so that they can find other pykaldi modules and the clif shared library inside the installed package.

@dmitriy-serdyuk
Copy link
Author

I am building with cmake, but the difference is that I want a wheel runnable on a different machine. So I run python setup.py bdist_wheel -d ./.

Next, I'm using the auditwheel tool to include all .so files inside the wheel. I was able to embed libkaldi_base.so, but not _clif.so.

@dogancan
Copy link
Member

I am guessing that is because _clif.so is not an external library dependency but is part of the pykaldi package.

@dogancan
Copy link
Member

dogancan commented Dec 31, 2018

First few lines of kaldi/__init__.py might also be relevant. I no longer think this is relevant.

@dogancan
Copy link
Member

I am guessing this problem has to do with auditwheel editing RPATH of extension modules. Checking the RPATH of shared libs after they are modified by auditwheel might give a clue about what is going wrong. I tried to run auditwheel repair on my end but apparently I need to first build with an older toolchain so the wheel is compatible with "manylinux1_x86_64" ABI.

Can you try running the following on your end?

mkdir tmp
unzip <wheel-created-by-auditwheel> -d tmp
cd tmp/kaldi/base
readelf -d _kaldi_error.so | head -20

This is what I get when I run it on the vanilla wheel.

 readelf -d _kaldi_error.so | head -20

Dynamic section at offset 0x2d88 contains 31 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [_clif.so]
 0x0000000000000001 (NEEDED)             Shared library: [libkaldi-base.so]
 0x0000000000000001 (NEEDED)             Shared library: [libpython3.6m.so.1.0]
 0x0000000000000001 (NEEDED)             Shared library: [libstdc++.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
 0x000000000000000e (SONAME)             Library soname: [_kaldi_error.so]
 0x000000000000000f (RPATH)              Library rpath: [/home/dogan/tools/pykaldi/tools/kaldi/tools/openfst/lib:/usr/local/cuda/lib64:/home/dogan/anaconda2/envs/clif3/lib:/home/dogan/tools/pykaldi/tools/kaldi/src/lib:/home/dogan/tools/pykaldi/tools/kaldi/tools/openfst/lib:$ORIGIN/../util:$ORIGIN/../nnet3:$ORIGIN/../lm:$ORIGIN/../kws:$ORIGIN/../sgmm2:$ORIGIN/../decoder:$ORIGIN/../feat:$ORIGIN/../fstext:$ORIGIN/../online2:$ORIGIN/../transform:$ORIGIN/../tree:$ORIGIN/../cudamatrix:$ORIGIN/../lat:$ORIGIN/../__pycache__:$ORIGIN/../rnnlm:$ORIGIN/../gmm:$ORIGIN/../ivector:$ORIGIN/../matrix:$ORIGIN/../hmm:$ORIGIN/../tfrnnlm:$ORIGIN/../base:$ORIGIN/../chain:$ORIGIN/../itf:$ORIGIN/../lib]
 0x000000000000000c (INIT)               0x1208
 0x000000000000000d (FINI)               0x1d84
 0x0000000000000019 (INIT_ARRAY)         0x202d70
 0x000000000000001b (INIT_ARRAYSZ)       8 (bytes)
 0x000000000000001a (FINI_ARRAY)         0x202d78
 0x000000000000001c (FINI_ARRAYSZ)       8 (bytes)
 0x000000006ffffef5 (GNU_HASH)           0x1f0
 0x0000000000000005 (STRTAB)             0x5d0
 0x0000000000000006 (SYMTAB)             0x240

@dmitriy-serdyuk
Copy link
Author

For the modified wheel it is:

 readelf -d _kaldi_error.so | head -20

Dynamic section at offset 0x2d88 contains 31 entries:
  Tag        Type                         Name/Value
 0x0000000000000001 (NEEDED)             Shared library: [_clif.so]
 0x0000000000000001 (NEEDED)             Shared library: [libkaldi-base-d68bbe48.so]
 0x0000000000000001 (NEEDED)             Shared library: [libpython3.5m.so.1.0]
 0x0000000000000001 (NEEDED)             Shared library: [libstdc++-62affc63.so.6.0.21]
 0x0000000000000001 (NEEDED)             Shared library: [libgcc_s-c77f8044.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libc-2-05b841ea.23.so]
 0x000000000000000e (SONAME)             Library soname: [_kaldi_error.so]
 0x000000000000000f (RPATH)              Library rpath: [$ORIGIN/../.libs]
 0x000000000000000c (INIT)               0x11a0
 0x000000000000000d (FINI)               0x1d14
 0x0000000000000019 (INIT_ARRAY)         0x202d70
 0x000000000000001b (INIT_ARRAYSZ)       8 (bytes)
 0x000000000000001a (FINI_ARRAY)         0x202d78
 0x000000000000001c (FINI_ARRAYSZ)       8 (bytes)
 0x000000006ffffef5 (GNU_HASH)           0x1f0
 0x0000000000000005 (STRTAB)             0x207268
 0x0000000000000006 (SYMTAB)             0x240

@dogancan
Copy link
Member

Yeah it seems auditwheel is not appending to RPATH but instead overwriting it. Relevant issue.

@dogancan
Copy link
Member

dogancan commented Dec 31, 2018

Can you run the following as well?

cd tmp/kaldi/.libs
ls -ltr

@dogancan
Copy link
Member

I think we can fix the RPATH problem by editing this function.

I think all needs to be done is to set RPATH to

$ORIGIN/../libs:$ORIGIN/../util:$ORIGIN/../nnet3:$ORIGIN/../lm:$ORIGIN/../kws:$ORIGIN/../sgmm2:$ORIGIN/../decoder:$ORIGIN/../feat:$ORIGIN/../fstext:$ORIGIN/../online2:$ORIGIN/../transform:$ORIGIN/../tree:$ORIGIN/../cudamatrix:$ORIGIN/../lat:$ORIGIN/../__pycache__:$ORIGIN/../rnnlm:$ORIGIN/../gmm:$ORIGIN/../ivector:$ORIGIN/../matrix:$ORIGIN/../hmm:$ORIGIN/../tfrnnlm:$ORIGIN/../base:$ORIGIN/../chain:$ORIGIN/../itf:$ORIGIN/../lib

instead of

$ORIGIN/../libs

@dmitriy-serdyuk
Copy link
Author

Thanks! This is very helpful!

@dmitriy-serdyuk
Copy link
Author

# ls -ltr
total 593992
-rwxr-xr-x 1 root root   3996768 Dec 30 21:37 libc-2-05b841ea.23.so
-rwxr-xr-x 1 root root  26212464 Dec 30 21:40 libfst-201beb5d.so.10.0.0
-rwxr-xr-x 1 root root   3640008 Dec 30 21:40 libkaldi-transform-8b82f1a0.so
-rwxr-xr-x 1 root root  46869784 Dec 30 21:40 libkaldi-lat-af312041.so
-rw-r--r-- 1 root root    193168 Dec 30 21:40 libcblas-0511b056.so.3.0
-rwxr-xr-x 1 root root   5032880 Dec 30 21:40 libkaldi-tree-8d9080fc.so
-rwxr-xr-x 1 root root  36723984 Dec 30 21:40 libkaldi-nnet2-1ccb99aa.so
-rwxr-xr-x 1 root root   2229912 Dec 30 21:40 libpthread-2-f045d9ab.23.so
-rwxr-xr-x 1 root root   5370376 Dec 30 21:40 libkaldi-matrix-b4e155c1.so
-rwxr-xr-x 1 root root  15628432 Dec 30 21:40 libkaldi-hmm-e8402a2a.so
-rwxr-xr-x 1 root root   2483320 Dec 30 21:40 libkaldi-feat-a9f3d716.so
-rw-r--r-- 1 root root     96920 Dec 30 21:40 libgcc_s-c77f8044.so.1
-rw-r--r-- 1 root root     21544 Dec 30 21:40 libdl-2-6104b774.23.so
-rw-r--r-- 1 root root   4137496 Dec 30 21:40 libatlas-aa548a16.so.3.0
-rw-r--r-- 1 root root   2631088 Dec 30 21:40 libstdc++-62affc63.so.6.0.21
-rwxr-xr-x 1 root root   3624600 Dec 30 21:40 libkaldi-sgmm2-ad236f47.so
-rwxr-xr-x 1 root root   5414536 Dec 30 21:40 libkaldi-lm-c7150916.so
-rwxr-xr-x 1 root root  32143744 Dec 30 21:40 libkaldi-kws-ab29bf80.so
-rwxr-xr-x 1 root root   3173392 Dec 30 21:40 libkaldi-gmm-129ff5ed.so
-rwxr-xr-x 1 root root   5458672 Dec 30 21:40 libkaldi-fstext-6cf8b03d.so
-rw-r--r-- 1 root root   1407288 Dec 30 21:40 libgfortran-88599953.so.3.0.0
-rw-r--r-- 1 root root    454160 Dec 30 21:40 liblapack_atlas-c3fb2ebc.so.3.0
-rwxr-xr-x 1 root root   3096688 Dec 30 21:40 libkaldi-util-1798c31e.so
-rwxr-xr-x 1 root root  17100576 Dec 30 21:40 libkaldi-online2-11df9adb.so
-rwxr-xr-x 1 root root  65259560 Dec 30 21:41 libkaldi-nnet3-13c72bd0.so
-rw-r--r-- 1 root root    267968 Dec 30 21:41 libquadmath-99889722.so.0.0.0
-rw-r--r-- 1 root root   1097496 Dec 30 21:41 libm-2-8c60f2bc.23.so
-rwxr-xr-x 1 root root   8512448 Dec 30 21:41 libkaldi-rnnlm-dab76bc8.so
-rwxr-xr-x 1 root root   2397984 Dec 30 21:41 libkaldi-ivector-dc494efc.so
-rwxr-xr-x 1 root root   2791360 Dec 30 21:41 libkaldi-cudamatrix-c23f53f9.so
-rwxr-xr-x 1 root root    710112 Dec 30 21:41 libkaldi-base-d68bbe48.so
-rw-r--r-- 1 root root    198408 Dec 30 21:41 libf77blas-d437c2dc.so.3.0
-rwxr-xr-x 1 root root 218226872 Dec 30 21:41 libfstscript-2d80e22d.so.10.0.0
-rwxr-xr-x 1 root root  36527192 Dec 30 21:41 libkaldi-decoder-9f29b929.so
-rwxr-xr-x 1 root root  45044696 Dec 30 21:41 libkaldi-chain-c898f267.so

@dogancan
Copy link
Member

I think we can get away with the following monkey patch until auditwheel fixes their code. This preserves RPATH directories that start with $ORIGIN. I am not sure if this change to patchelf_set_rpath is a general enough solution but it should do the job for us.

cat ./auditwheel

#!/usr/bin/env python

# -*- coding: utf-8 -*-
import re
import sys

import logging
from os.path import relpath, dirname
from os.path import join as pjoin
from subprocess import check_call, check_output

from auditwheel.main import main
from auditwheel import repair

logger = logging.getLogger('auditwheel.repair')

def patchelf_set_rpath(fn, libdir):
    rpath = check_output(['patchelf', '--print-rpath', fn]).decode("utf-8").strip()
    rpath = list(filter(lambda x: x.startswith('$ORIGIN'), rpath.split(":")))
    rpath.append(pjoin('$ORIGIN', relpath(libdir, dirname(fn))))
    rpath = ":".join(rpath)
    logger.debug('Setting RPATH: %s to "%s"', fn, rpath)
    check_call(['patchelf', '--force-rpath', '--set-rpath', rpath, fn])

repair.patchelf_set_rpath = patchelf_set_rpath

if __name__ == '__main__':
    sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
    sys.exit(main())

@dmitriy-serdyuk
Copy link
Author

Yay! It worked!

@dmitriy-serdyuk
Copy link
Author

Are you interested in a script building wheel? I could submit a PR

@dogancan
Copy link
Member

Very much interested! Are you building it with the manylinux docker image?

@dmitriy-serdyuk
Copy link
Author

Not yet. So far I tried only with pykaldi/pykaldi docker and auditwheel --plat linux_x86_64 option.

@dogancan
Copy link
Member

Got it. Maybe we can build the wheel and upload it somewhere as part of docker image build on Travis.

@dogancan
Copy link
Member

@dmitriy-serdyuk I just pushed a change which might affect redistributable wheels. After this change, _clif.so will no longer be linked against libpython.so in non-debug builds. See the commit message for further info.

@dmitriy-serdyuk
Copy link
Author

Great, thanks!

@dmitriy-serdyuk
Copy link
Author

Unfortunately python library is still needed to compile CLIF.

manylinux docker is a huge pain to work with, they don't have libpython for the reason you mentioned. Also, it is really hard to compile python on this prehistorical CentOS 5. I give up for now.

Here is dockerfile (not working) so far:

FROM quay.io/pypa/manylinux1_x86_64

# Install necessary system packages
RUN yum -y install \
    graphviz \
    atlas-devel \
    subversion \
    wget \
    zlib-devel \
    xz

ADD https://www.openssl.org/source/openssl-1.0.2q.tar.gz /

RUN tar xvf openssl-1.0.2q.tar.gz \
    && cd openssl-1.0.2q \
    && ./config && make && make install

ADD http://download.zeromq.org/zeromq-4.0.3.tar.gz /

RUN tar xf zeromq-4.0.3.tar.gz \
    && cd zeromq-4.0.3 \
    && ./configure && make && make install

ADD https://github.com/Kitware/CMake/releases/download/v3.13.3/cmake-3.13.3.tar.gz /

RUN tar xvf cmake-3.13.3.tar.gz && cd cmake-3.13.3 && ./bootstrap && make && make install

RUN cmake --version

# Copy pykaldi directory into the container
COPY . /pykaldi

ENV PYTHON2PATH /opt/python/cp27-cp27m/bin
ENV PYTHON3PATH /opt/python/cp36-cp36m/bin
ENV PATH ${PYTHON2PATH}:${PYTHON3PATH}:${PATH}

RUN ${PYTHON2PATH}/python -m pip install --upgrade pip \
        numpy \
        setuptools \
        pyparsing \
        jupyter \
        ninja

RUN cd /pykaldi/tools \
    && ./check_dependencies.sh \
    && ./install_protobuf.sh \
    && ./install_clif.sh \
    && ./install_kaldi.sh \
    && cd .. \
    && python setup.py install

@dogancan
Copy link
Member

dogancan commented Jan 17, 2019

Thanks for the effort you put in! I don't know if CLIF people had a reason to link with libpython. We are building and packaging the same CLIF runtime library (which is the part linking with libpython) as part of pykaldi and we don't need to link against libpython. To be honest, current state of CLIF is the reason why I haven't invested more time into distributing pykaldi wheels. I was hoping they would release a new version of CLIF that you could install from a package manager and we wouldn't have to deal with these issues when distributing pykaldi. I was also hoping that would happen some time last year but nothing yet.

Do you need to build on Centos 5? Who is still using that? :) @vrmpx is building our conda package on Centos 7 and that seems to work for most people. manylinux2010 image is Centos 6 which might be significantly easier to work with. I think even pytorch people are building their packages on Centos 6.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants