我想编写一个简单的JNI包装器,用于使用具有C ++ API的Festival text-to-speech(或任何其他)库。我有以下文件:
Main.java:
public class Main {
static {
System.loadLibrary("TTSWrapper");
}
private native void FestivalSayHello();
public static void main(String[] args) {
new Main().FestivalSayHello();
}
}
生成Main.h:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Main */
#ifndef _Included_Main
#define _Included_Main
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: Main
* Method: FestivalSayHello
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_Main_FestivalSayHello
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
FestivalWrapper.cpp:
#include <iostream>
#include <jni.h>
#include "Main.h"
#include "include/festival.h"
JNIEXPORT void JNICALL Java_Main_FestivalSayHello(JNIEnv *env, jobject thisObj) {
EST_Wave wave;
int heap_size = 210000; // default scheme heap size
int load_init_files = 1; // we want the festival init files loaded
festival_initialize(load_init_files,heap_size);
festival_say_file("/etc/motd");
festival_eval_command("(voice_ked_diphone)");
festival_say_text("hello world");
festival_text_to_wave("hello world",wave);
wave.save("output.wav","riff");
festival_wait_for_spooler();
return;
}
生成文件:
CLASS_PATH = ../bin
all : libTTSWrapper.so
libTTSWrapper.so : FestivalWrapper.o Main.h
g++ -m64 -fPIC -shared -o $@ $<
FestivalWrapper.o : FestivalWrapper.cpp Main.h
g++ -fPIC \
-I"/usr/lib/jvm/java-7-openjdk-amd64/include" \
-I"/home/TTS_tools/Festival/festival/src" \
-I"/home/TTS_tools/Festival/speech_tools/include" \
-L"/home/TTS_tools/Festival/festival/src/lib" \
-L"/home/TTS_tools/Festival/speech_tools/lib" \
-lFestival \
-lestools \
-lestbase \
-leststring \
-lncurses \
-c $< \
-o $@
Main.h : Main.class
javah -classpath $(CLASS_PATH) $*
运行时出现以下错误:
/usr/lib/jvm/java-7-openjdk-amd64/bin/java: symbol lookup error: /home/workspace/TTS/jni/libTTSWrapper.so: undefined symbol: _ZN8EST_WaveC1Ev
请问你能帮我找出问题所在?我不确定-m64和-fPIC是否必要。
注1:nm libTTSWrapper.so | grep EST_Wave
列出导致错误的符号,即使我删除了-L和-l行。
注意2:Festival是静态库的组合。
注意3:这个问题不是特定于库的,我也遇到了与另一个库(Ekho)相同的问题。问题是我不知道如何链接第三方库。
更新:我仍然不确定,但我猜问题是因为Festival没有与-fPIC
选项相关联。尽管符号出现在生成的共享库中,但我认为它们无法正确引用。当我试图创建一个简单的可执行文件时,我使用了一个链接到静态库的共享库,在纯C中我实现了这一点。我必须从一个用它构建的目标文件中创建 .a 文件。 -fPIC
选项以及共享库也需要-fPIC
选项。
答案 0 :(得分:0)
我不确定您的代码是如何打包的,但包名对JNI非常重要。另外,我不建议使用默认包(在任何时候,尤其是在这种情况下:p)
假设您的包被调用
package groove.FestivaWrapper
然后你的JNI电话必须看起来像这样
groove_FestivalWrapper_FestivalSayHello
否则JNI将无法确定要拨打的电话。
答案 1 :(得分:0)
你有两个问题。第一个问题是,当您构建FestivalWrapper.o
时,忽略 -L
和-l
选项 - 它们仅由链接器使用,而不是由编译器。这些选项需要传递给链接器。你的makefile看起来应该更像:
CLASS_PATH = ../bin
all : libTTSWrapper.so
libTTSWrapper.so : FestivalWrapper.o Main.h
g++ -m64 -fPIC -shared -o $@ $< \
-L"/home/TTS_tools/Festival/festival/src/lib" \
-L"/home/TTS_tools/Festival/speech_tools/lib" \
-lFestival \
-lestools \
-lestbase \
-leststring \
-lncurses
FestivalWrapper.o : FestivalWrapper.cpp Main.h
g++ -fPIC \
-I"/usr/lib/jvm/java-7-openjdk-amd64/include" \
-I"/home/TTS_tools/Festival/festival/src" \
-I"/home/TTS_tools/Festival/speech_tools/include" \
-c $< \
-o $@
Main.h : Main.class
javah -classpath $(CLASS_PATH) $*
即。您必须将-L
和-l
选项移动到生成.so
文件的项目,即执行链接时。
你的第二个问题是你没有用-fPIC
编辑节日。是的,这会阻止链接,因为所有 .so
64位文件必须使用-fPIC
进行编译才能进行ABI编辑。你会收到如下错误:
/usr/bin/ld: ../festival/src/lib/libFestival.a(festival.o): relocation R_X86_64_32 against `.rodata.str1.1' can not be used when making a shared object; recompile with -fPIC
../festival/src/lib/libFestival.a: error adding symbols: Bad value
库不遵循标准配置约定 - 即在运行configure脚本之前尝试设置CFLAGS
根本不起作用。
使用speech_tools
为festival
个文件构建-fPIC
和.a
:
export CC_OTHER_FLAGS=-fPIC
在为每个包运行configure
之前。这将确保将-fPIC
标志传递到编译的所有阶段。