【问题标题】:Java JNI "symbol lookup error" with c++ library带有 C++ 库的 Java JNI“符号查找错误”
【发布时间】:2013-09-30 15:40:16
【问题描述】:

我正在树莓派上构建一个小应用程序。 我有一个 JVM,它试图访问一个名为“RCSwitch”的 C++ 库 我创建了一个 JavaClass

public class NativeRCSwitchAdapter {

    private static final NativeRCSwitchAdapter instance = new NativeRCSwitchAdapter();

    public static NativeRCSwitchAdapter getInstance(){
        return instance;
    }
    private NativeRCSwitchAdapter(){};

    static{
        String path = NativeRCSwitchAdapter.class.getProtectionDomain().getCodeSource().getLocation().getPath();
        System.load(path + "NativeRCSwitchAdapter.so");
}

    // methods to redirect to native layer (C++)
    public native void switchOn(String group, String channel);
    public native void switchOff(String group, String channel);
}

然后我运行 javac & javah 让 java 为我生成我的头文件。

我创建了一个 c++ 文件:

#include "NativeRCSwitchAdapter.h"
#include "RCSwitch.h"
#include <stdio.h>
#include <iostream>

using namespace std;

JNIEXPORT void JNICALL Java_NativeRCSwitchAdapter_switchOn(JNIEnv * env, jobject obj, jstring jsGroup, jstring jsChannel ){
cout<<"teststring output"<<endl;
const char *csGroup = env->GetStringUTFChars(jsGroup, 0);
const char *csChannel = env->GetStringUTFChars(jsChannel, 0);

char sGroup[6];
char sChannel[6];

for (int i = 0; i<5; i++) {
    sGroup[i] = csGroup[i];
    sChannel[i] = csChannel[i];
}
sGroup[5] = '\0';
sChannel[5] = '\0';

cout<<"ONON"<<endl;
cout<<sGroup<<endl;
cout<<sChannel<<endl;


RCSwitch mySwitch = RCSwitch();

//for testing purposes set to the ELRO Power Plugs
mySwitch.setPulseLength(300);
mySwitch.enableTransmit(0);
mySwitch.setRepeatTransmit(3);

mySwitch.switchOn(sGroup, sChannel);
}

现在这个文件使用了 RCSwitch 库,而 RCSwitch 库又使用了 WiringPi 库。

现在如果我编译我运行这个:

g++ -shared -I/usr/jdk1.8.0/include -I/usr/jdk1.8.0/include/linux NativeRCSwitchAdapter.cpp -o NativeRCSwitchAdapter.so

但是,如果从 java 启动所有内容,我会收到此错误:(简单的 main,创建我的对象的实例并运行 switchOn()

java: symbol lookup error: /home/pi/applications/Pi-jAutomation433/RCSwitchJNIWrapper/src/NativeRCSwitchAdapter.so: undefined symbol: _ZN8RCSwitchC1Ev

自从我上次用 C 编码以来,已经有时间了,所以请原谅我,但我相信这与编译器的链接阶段有关?还是编译器会自动检查所有依赖项,然后检查它们的依赖项,直到找不到更多依赖项,然后将它们很好地链接在一起并将其包装在应用程序中?

哦,如果有人关心,这里是深入了解的 repo: Github repo

感谢您的帮助!

更新

好的,所以我设法消除了这个错误。结果(好吧,我已经知道了,但是是的)当谈到 C++ 编译器知识时,我很安静。无论如何,我设法改变了错误。我不知道我必须明确告诉 g++ 也包括 RCSwitch.cpp。好的,现在我做到了。下一个错误;-) 我想这一次应该很容易解决。我得到一个未定义的符号“pinMode”。 该符号是wiringPi 库的一部分。我是否必须包含在我的 java 文件中执行的所有 c 库?还是只有我访问的那个和之后的任何东西对 java 无关紧要?

【问题讨论】:

  • RCSwitch() 在哪里定义?如果它在某个库中,那么您将需要弄清楚如何链接您的自定义库以便包含另一个库,以动态加载器自动将其引入的方式引用,或者简单地手动加载在加载需要它的自定义库之前,来自 Java 的其他库。如果该库不是 C++ 库,您还需要确保它的标头是 extern "C" {}

标签: java c++ java-native-interface embedded


【解决方案1】:

您的本机函数声明被 c++ 编译器破坏。在您的声明周围添加 extern "C" 以解决问题。

#ifdef __cplusplus
extern "C" {
#endif  /* __cplusplus */
JNIEXPORT void JNICALL Java_NativeRCSwitchAdapter_switchOn(JNIEnv * env, jobject obj, jstring jsGroup, jstring jsChannel ){
#ifdef __cplusplus
}
#endif  /* __cplusplus */

编辑: 您需要在创建共享库时包含所有其他对象/库。

请参阅此Dynamic Link Library Q/A。

【讨论】:

  • 这确实可能是一个问题,但它似乎与运行时错误消息不匹配。不是 JNI 函数找不到。
  • 好点。我的猜测是语法RCSwitch mySwitch = RCSwitch(); 他试图调用无参数构造函数。那应该只是RCSwitch mySwitch;
  • 这不是必需的。它是在生成的头文件中完成的,这个头文件包含在他的.cpp文件中,足以告诉编译器这个方法是extern "C"。此外,这不是他错误的根源。并且RCSwitch mySwitch; 等同于RCSwitch mySwitch = RCSwitch(); -1
  • g++ -shared -I/usr/jdk1.8.0/include -I/usr/jdk1.8.0/include/linux NativeRCSwitchAdapter.cpp -o NativeRCSwitchAdapter.so RCSwitch 类的实现是否在 NativeRCSwitchAdapter.cpp 文件中?如果没有,那么您需要将该编译对象链接到您的 .so 中,或者也加载该库。
  • 好的,所以编译器不会自动查找依赖项(我来自 spring,依赖项注入会自动发生)。如何将我需要的“所有”库也放入 .so 或以其他方式将它们链接到我的 NativeRCSwitchAdapter.so?
猜你喜欢
  • 2018-06-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-21
  • 1970-01-01
相关资源
最近更新 更多