最近项目要求需要重新写一个kaldi的新模块,并且要用java去调用kaldi的这个模块。因为之前没有接触过JNI以及对kaldi底层配置,编译原理不熟悉,导致自己吃了很多碰,浪费了好多时间,再外加上kaldi这块的资料是真的不太多,因此自己写一个博客,一方面作为备忘录,另一方面希望以后能帮到有些kaldi的学习和使用者。
这个过程中有两篇博客对我帮助很大,在这对这两位表示感谢,帮了很大的忙:
[1]https://blog.csdn.net/hongquan1991/article/details/12426615
这位作者对linux/Ubuntu 下使用 java 调用 so 动态链接库步骤讲很好,我也是从这去了解如何去调用so文件的
[2] https://github.com/ahmetaa/kaldi-jni
这个项目的Makefile文件写的很好。我也主要借鉴了他的makefile文件
接下来步入正题:
因为java的jni要调用c++的函数的话,需要调用cpp的动态链接库(so文件)而不是静态链接库(o文件),但是kaldi默认是生成静态链接库,所以我们最需要重新编译kaldi,让他能生成动态链接库
第一步:在kaldi/src目录下make clean(清楚之前编译文件)
第二步:打开kaldi/src目录下run_config.sh文件,文件如下
# Kaldi compiled with static, cuda and openblas.
# For further dynamic linking based on kaldi (usually no cuda),
# compile openfst and kaldi with -fPIC by modifying
# ../tools/Makefile and kaldi.mk with "CXXFLAGS += -fPIC".
# kaldi.mk is generated by running ./configure below.
./configure --static \
--use-cuda=yes --cudatk-dir=/usr/local/cuda-9.0 \
--mathlib=ATLAS --atlas-root=../tools/ATLAS_headers/\
--threaded-math=no --static-math=yes \
--static-fst=yes --fst-root=../tools/openfst
将"--static" 改为"--shared" ,保存并退出。
第三步:打开kaldi/tools目录下Makefile文件,在文件第五行处加上
CXXFLAGS += -fPIC
保存并退出。
第四步:打开kaldi/src目录下Makefile文件,在SUBDIRS 变量下,加入你自己新模块的目录(我的是叫testbin)
SUBDIRS = base matrix util feat cudafeat tree gmm transform \
fstext hmm lm decoder lat kws cudamatrix nnet \
bin fstbin gmmbin fgmmbin featbin cudafeatbin \
nnetbin latbin sgmm2 sgmm2bin nnet2 nnet3 rnnlm chain nnet3bin nnet2bin kwsbin \
ivector ivectorbin online2 online2bin lmbin chainbin rnnlmbin \
cudadecoder cudadecoderbin testbin
并在添加依赖项
### Dependency list ###
# this is necessary for correct parallel compilation
#1)The tools depend on all the libraries
bin fstbin gmmbin fgmmbin sgmm2bin featbin cudafeatbin nnetbin nnet2bin nnet3bin chainbin latbin ivectorbin lmbin kwsbin online2bin rnnlmbin testbin cudadecoderbin: \
base matrix util feat cudafeat tree gmm transform sgmm2 fstext hmm \
lm decoder lat cudamatrix nnet nnet2 nnet3 ivector chain kws online2 rnnlm \
cudadecoder
第五步编译kaldi,你会发现这次的kaldi比之前在src下多了几文件夹,打开src下lib文件夹你就会发现你生成的so在这里:
libhh.so@ --> /data/kaldi-caser/src/testbin/libhh.so
libkaldi-base.so@ --> /data/kaldi-caser/src/base/libkaldi-base.so
libkaldi-chain.so@ --> /data/kaldi-caser/src/chain/libkaldi-chain.so
libkaldi-cudadecoder.so@ --> /data/kaldi-caser/src/cudadecoder/libkaldi-cudadecoder.so
libkaldi-cudafeat.so@ --> /data/kaldi-caser/src/cudafeat/libkaldi-cudafeat.so
libkaldi-cudamatrix.so@ --> /data/kaldi-caser/src/cudamatrix/libkaldi-cudamatrix.so
libkaldi-decoder.so@ --> /data/kaldi-caser/src/decoder/libkaldi-decoder.so
libkaldi-feat.so@ --> /data/kaldi-caser/src/feat/libkaldi-feat.so
libkaldi-fstext.so@ --> /data/kaldi-caser/src/fstext/libkaldi-fstext.so
libkaldi-gmm.so@ --> /data/kaldi-caser/src/gmm/libkaldi-gmm.so
libkaldi-hmm.so@ --> /data/kaldi-caser/src/hmm/libkaldi-hmm.so
libkaldi-ivector.so@ --> /data/kaldi-caser/src/ivector/libkaldi-ivector.so
libkaldi-kws.so@ --> /data/kaldi-caser/src/kws/libkaldi-kws.so
libkaldi-lat.so@ --> /data/kaldi-caser/src/lat/libkaldi-lat.so
libkaldi-lm.so@ --> /data/kaldi-caser/src/lm/libkaldi-lm.so
libkaldi-matrix.so@ --> /data/kaldi-caser/src/matrix/libkaldi-matrix.so
libkaldi-nnet.so@ --> /data/kaldi-caser/src/nnet/libkaldi-nnet.so
libkaldi-nnet2.so@ --> /data/kaldi-caser/src/nnet2/libkaldi-nnet2.so
libkaldi-nnet3.so@ --> /data/kaldi-caser/src/nnet3/libkaldi-nnet3.so
libkaldi-online2.so@ --> /data/kaldi-caser/src/online2/libkaldi-online2.so
libkaldi-rnnlm.so@ --> /data/kaldi-caser/src/rnnlm/libkaldi-rnnlm.so
libkaldi-sgmm2.so@ --> /data/kaldi-caser/src/sgmm2/libkaldi-sgmm2.so
libkaldi-transform.so@ --> /data/kaldi-caser/src/transform/libkaldi-transform.so
libkaldi-tree.so@ --> /data/kaldi-caser/src/tree/libkaldi-tree.so
libkaldi-util.so@ --> /data/kaldi-caser/src/util/libkaldi-util.so
testbin下的makefile文件,仿照链接2所写,其中加了一些我自己模块所以来的kaldi库,跟链接2大差不差,我也贴出来了
all:
EXTRA_CXXFLAGS = -Wno-sign-compare
include ../kaldi.mk
LDFLAGS += $(CUDA_LDFLAGS)
LDLIBS += $(CUDA_LDLIBS)
JNI_HEADERS_1 = /data/java/jdk-13.0.1/include
JNI_HEADERS_2 = /data/java/jdk-13.0.1/include/linux
cuda-compiled.o: ../kaldi.mk
OBJFILES = hh.o
LIBNAME = hh
TESTFILES =
ADDLIBS = ../hmm/kaldi-hmm.a ../feat/kaldi-feat.a \
../transform/kaldi-transform.a ../gmm/kaldi-gmm.a \
../tree/kaldi-tree.a ../util/kaldi-util.a ../matrix/kaldi-matrix.a \
../base/kaldi-base.a ../nnet3/kaldi-nnet3.a ../chain/kaldi-chain.a \
../cudamatrix/kaldi-cudamatrix.a ../decoder/kaldi-decoder.a \
../lat/kaldi-lat.a ../fstext/kaldi-fstext.a
CXXFLAGS += -I$(JNI_HEADERS_1)
CXXFLAGS += -I$(JNI_HEADERS_2)
include ../makefiles/default_rules.mk
~
~
~
其中libhh.so为我的新模块的so文件,至此大功告成!
至于JNI怎么调用,以及cpp文件应该怎么写,请看链接一 写的很好,肯定能看懂!