2014-10-30 90 views
0

我想编写一个简单的JNI的包装使用节文本到语音(或任何其它),其中有一个C++ API库。我有以下文件:JNI包装的C++库和未定义的符号错误

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 [email protected] $< 

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 [email protected] 

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:节日是静态库的组合。

注意3:这个问题不是库特定的,我也遇到了与另一个库(Ekho)相同的问题。问题是我不知道如何链接第三方库。

更新:我仍然不确定,但我想这个问题是因为节日没有链接-fPIC选项。虽然符号出现在生成的共享库中,但我认为它们不能被正确引用。我达到了这个,而我试图让使用它链接到静态库的共享库的简单可执行,纯C.我必须要创建从-fPIC选项生成目标文件中的.A文件,并且还共享库也需要-fPIC选项。

+0

问题是太特定的外部图书馆..你需要提供代码..什么是错误?代码是否导致它?它只是你的生成文件,无法找到文件?等等。仅仅makefile就不够好。 – Brandon 2014-10-30 19:08:56

+0

确切的错误总是相关的 – Eric 2014-10-31 07:21:15

+0

@Brandon:我编辑了这个问题,并添加了源代码。 – groove 2014-10-31 07:23:13

回答

0

我不知道你的代码是如何打包,但包名称是JNI非常重要。此外,我不会建议使用默认的包(在任何时候,尤其是在这种情况下:P)

假设你的包被称为 package groove.FestivaWrapper

那么你的JNI调用有看起来像这样 groove_FestivalWrapper_FestivalSayHello

否则JNI将不知道要调用什么。

+0

如果您提到了包裹问题,它仍会编译吗? – groove 2014-10-31 07:34:29

+0

如果我没记错的话。如果.h匹配.cpp,那么编译器不会抱怨。然后在运行时,JNI运行时不会找到任何东西,并且很难调试痛苦。 – Eric 2014-10-31 07:35:46

+0

但是,您得到此错误消息可能不是问题。 – Eric 2014-10-31 07:38:16

0

你有两个问题。第一个问题是,当你正在建设FestivalWrapper.o,它忽略-L-l选择 - 他们只使用的连接器,而不是由编译器。这些选项需要传递给链接器。你的Makefile应该更像:

CLASS_PATH = ../bin 

all : libTTSWrapper.so 

libTTSWrapper.so : FestivalWrapper.o Main.h 
    g++ -m64 -fPIC -shared -o [email protected] $< \ 
    -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 [email protected] 

Main.h : Main.class 
    javah -classpath $(CLASS_PATH) $* 

即你必须移动-L-l选项生成的文件.so,进行连接时,这是该项目。

你的第二个问题是,你还没有编辑节日-fPIC。是的,这将阻止链接,因为全部.so如果要编译ABI,必须使用-fPIC编译64位文件。你会得到这样的错误:

/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 

的库不按标准配置约定 - 即试图运行配置脚本根本不起作用之前设置CFLAGS

要为.a文件你建立speech_toolsfestival-fPIC

export CC_OTHER_FLAGS=-fPIC 

每个包运行configure之前。这将确保-fPIC标志被传递到编译的所有阶段。

+0

感谢您的详细解答。不幸的是,“export ...”命令不适用于Ekho TTS库。所以,如果我没有做错任何事情,恐怕这个程序不适用于所有的图书馆。 – groove 2014-11-12 08:23:24

+0

speech_tools和festival包不遵循'configure' /'autoconf'规范,这就是为什么当构建那些在构建中获得'-fPIC'标志时不得不使用'CC_OTHER_FLAGS'的原因。 Ekho TTS使用标准的autoconf机制,因此设置'export CXXFLAGS =“ - O -fPIC”'和'export CFLAGS =“ - O -fPIC”'应该对该库有理想的效果。 – Petesh 2014-11-12 08:34:11