java - 在 ARM 上使用 BlueCove-DBus。 Linux 上 C 库和 Java 代码 (JNI) 之间的链接器错误

标签 java c linux java-native-interface bluecove

目前,我正在尝试在我的 Raspberry Pi 3 上使用蓝牙,在尝试使用其他库但结果不完整后,我选择了 BlueCove over DBus(快照 2.1.1),因为它看起来基本上是完整的,并且没有强制使用 GPL 许可证。不幸的是,给定的编译库不包含 ARM 的 native ,因此经过大量试验和错误,我编译了此 API 的 native 及其先决条件。至少我是这么想的。

我在尝试使用 API 时收到 UnsatisfiedLinkError。我可以确认该库正在加载到 JVM 中,并且在调用 native 方法时会出现错误。

java.lang.UnsatisfiedLinkError: com.intel.bluetooth.BluetoothStackBlueZDBus.getLibraryVersionNative()I at com.intel.bluetooth.BluetoothStackBlueZDBus.getLibraryVersionNative(Native Method) at com.intel.bluetooth.BluetoothStackBlueZDBus.getLibraryVersion(BluetoothStackBlueZDBus.java:160) at com.intel.bluetooth.BlueCoveImpl.detectStack(BlueCoveImpl.java:471) at com.intel.bluetooth.BlueCoveImpl.access$500(BlueCoveImpl.java:69) at com.intel.bluetooth.BlueCoveImpl$1.run(BlueCoveImpl.java:1044) at java.base/java.security.AccessController.doPrivileged(Native Method) at com.intel.bluetooth.BlueCoveImpl.detectStackPrivileged(BlueCoveImpl.java:1042) at com.intel.bluetooth.BlueCoveImpl.getBluetoothStack(BlueCoveImpl.java:1035) at javax.bluetooth.LocalDevice.getLocalDeviceInstance(LocalDevice.java:75) at javax.bluetooth.LocalDevice.getLocalDevice(LocalDevice.java:95) at tech.delta.system_automation.server.bin.connections.bluetooth.RemoteDeviceDiscovery.discoverDevices(RemoteDeviceDiscovery.java:54) at tech.delta.system_automation.server.bin.Autonoma_Server.main(Autonoma_Server.java:40)

这是我初始化进程的地方

LocalDevice d = LocalDevice.getLocalDevice();

这是 BlueCove API 中 Java 代码失败的地方

private native int getLibraryVersionNative();

public int getLibraryVersion() throws BluetoothStateException {
    int version = getLibraryVersionNative();
    if (version != BLUECOVE_DBUS_VERSION) {
        DebugLog.fatal("BlueCove native library version mismatch " + version + " expected " + BLUECOVE_DBUS_VERSION);
        throw new BluetoothStateException("BlueCove native library version mismatch");
    }
    return version;
}

这是它尝试使用的 C 代码

JNIEXPORT jint JNICALL Java_com_intel_bluetooth_BluetoothStackBlueZDBus_getLibraryVersionNative
(JNIEnv *env, jobject peer) {
    return com_intel_bluetooth_BluetoothStackBlueZDBus_BLUECOVE_DBUS_VERSION;
}

现在我只能假设代码在带有预编译 native 的 x86/64 系统上使用时可以工作,但我没有太多运气,说实话,我没有使用 JNI(我的 C)的经验知识有限,我这辈子还没写过Makefile。但我怀疑这可能是 C 端的链接问题。

我认为编译 C 代码时标志存在问题,该代码拒绝使用编译它的 jar。我怀疑这是因为必须将 lib 文件从 libbluecovez.so 重命名为 libbluecovez_arm.so。但我不能确定,我正在寻找一些更有经验的用户,他们可能能够为我指明正确的方向。

这里是Makefile供引用

# @version $Revision: 2829 $ ($Author: skarzhevskyy $) $Date: 2009-03-03 03:44:45 -0500 (Tue, 03 Mar 2009) $
#
# Created by Francois Kooman
#
# Use this file in case you don't have ant or maven installed on the system
# Usage: make all
#

BLUECOVE_VERSION=2.1.1-SNAPSHOT

BLUECOVE_JAR=../bluecove/target/bluecove-${BLUECOVE_VERSION}.jar
JAVAH=$(JAVA_HOME)/bin/javah
JAVAC=$(JAVA_HOME)/bin/javac
JAVAC_OPTIONS=-g -source 1.5 -target 1.5
CC=gcc
CFLAGS=-Wall -fPIC -fno-stack-protector # -Werror
# -nodefaultlibs ->  statically linked
CLIBFLAGS=$(CFLAGS) -nodefaultlibs -shared -Wl,-soname,libbluecovez-$(BLUECOVE_VERSION)
SRC_C_DIR=src/main/c
SRC_JAVA_DIR=src/main/java
CLASSES_DIR=target/classes
OBJ_DIR=target/native
JAVACLASSES=com.intel.bluetooth.BluetoothStackBlueZDBus com.intel.bluetooth.BluetoothStackBlueZDBusConsts com.intel.bluetooth.BluetoothStackBlueZDBusNativeTests org.bluecove.socket.LocalSocketImpl
LIBPOSTFIX=`uname -p | grep 64 | sed 's/.*64.*/_x64/g'`

TARGET_LIB=target/libbluecovez$(LIBPOSTFIX).so

DBUS_JAVA_LIBS_DIR=target
DBUS_JAVA_CLASSPATH=$(DBUS_JAVA_LIBS_DIR)/dbus.jar:$(DBUS_JAVA_LIBS_DIR)/unixsockets.jar
CLASSPATH=$(BLUECOVE_JAR):$(DBUS_JAVA_CLASSPATH)

all: classes jni-headers native-lib

classes:
    -@mkdir -p $(CLASSES_DIR)
    -@$(JAVAC) -d $(CLASSES_DIR) $(JAVAC_OPTIONS) -classpath $(CLASSPATH) \
    $(SRC_JAVA_DIR)/org/bluez/*.java $(SRC_JAVA_DIR)/com/intel/bluetooth/*.java $(SRC_JAVA_DIR)/org/bluecove/socket/*.java

jni-headers:
    -@$(JAVAH) -d $(SRC_C_DIR) \
    -classpath $(CLASSPATH):$(CLASSES_DIR) \
    $(JAVACLASSES)

native-lib:
    -@mkdir -p $(OBJ_DIR)
    -@cd $(OBJ_DIR) && \
    $(CC) $(CFLAGS) -c ../../$(SRC_C_DIR)/*.c -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux
    -@$(CC) $(CLIBFLAGS) -o $(TARGET_LIB) $(OBJ_DIR)/*.o
    -@strip $(TARGET_LIB)
    -@cp $(TARGET_LIB) $(CLASSES_DIR)/libbluecovez$(LIBPOSTFIX).so
    -@echo "Native library $(TARGET_LIB) created"
    -@echo "Shared library dependencies:"
    -@ldd -v $(TARGET_LIB)

clean:
    rm -rf target

我怀疑 Makefile 中的行是

CLIBFLAGS=$(CFLAGS) -nodefaultlibs -shared -Wl,-soname,libbluecovez-$(BLUECOVE_VERSION)

TARGET_LIB=target/libbluecovez$(LIBPOSTFIX).so

考虑到最终的 jar 名为 bluecove-bluez-2.1.1-SNAPSHOT.jar,lib 文件名为 libbluecovez_arm.so

如果有人能为我提供一些帮助,那就太好了。

更新,所以问题出在我的 Makefile 上,导致 Javah 出现问题,进而导致 C 编译器出现问题,这是我的问题的根源。

这是编译错误

Error: Could not find class file for 'com.intel.bluetooth.BluetoothStackBlueZDBus'.
Error: Could not find class file for 'com.intel.bluetooth.BluetoothStackBlueZDBusConsts'.
Error: Could not find class file for 'com.intel.bluetooth.BluetoothStackBlueZDBusNativeTests'.
Error: Could not find class file for 'org.bluecove.socket.LocalSocketImpl'.
Makefile:40: recipe for target 'jni-headers' failed
make: [jni-headers] Error 1 (ignored)
In file included from ../../src/main/c/BlueCoveBlueZ.c:26:0:
../../src/main/c/BlueCoveBlueZ.h:38:57: fatal error: com_intel_bluetooth_BluetoothStackBlueZDBus.h: No such file or di            rectory
 #include "com_intel_bluetooth_BluetoothStackBlueZDBus.h"
                                                         ^
compilation terminated.
In file included from ../../src/main/c/BlueCoveBlueZ_L2CAP.c:26:0:
../../src/main/c/BlueCoveBlueZ.h:38:57: fatal error: com_intel_bluetooth_BluetoothStackBlueZDBus.h: No such file or di            rectory
 #include "com_intel_bluetooth_BluetoothStackBlueZDBus.h"
                                                         ^
compilation terminated.
In file included from ../../src/main/c/BlueCoveBlueZ_L2CAPServer.c:26:0:
../../src/main/c/BlueCoveBlueZ.h:38:57: fatal error: com_intel_bluetooth_BluetoothStackBlueZDBus.h: No such file or di            rectory
 #include "com_intel_bluetooth_BluetoothStackBlueZDBus.h"
                                                         ^
compilation terminated.
In file included from ../../src/main/c/BlueCoveBlueZ_RFCOMM.c:26:0:
../../src/main/c/BlueCoveBlueZ.h:38:57: fatal error: com_intel_bluetooth_BluetoothStackBlueZDBus.h: No such file or di            rectory
 #include "com_intel_bluetooth_BluetoothStackBlueZDBus.h"
                                                         ^
compilation terminated.
In file included from ../../src/main/c/BlueCoveBlueZ_RFCOMMServer.c:26:0:
../../src/main/c/BlueCoveBlueZ.h:38:57: fatal error: com_intel_bluetooth_BluetoothStackBlueZDBus.h: No such file or di            rectory
 #include "com_intel_bluetooth_BluetoothStackBlueZDBus.h"
                                                         ^
compilation terminated.
In file included from ../../src/main/c/BlueCoveBlueZ_Tests.c:26:0:
../../src/main/c/BlueCoveBlueZ.h:38:57: fatal error: com_intel_bluetooth_BluetoothStackBlueZDBus.h: No such file or di            rectory
 #include "com_intel_bluetooth_BluetoothStackBlueZDBus.h"
                                                         ^
compilation terminated.
In file included from ../../src/main/c/BlueCoveLocalSocket.c:27:0:
../../src/main/c/BlueCoveLocalSocket.h:40:49: fatal error: org_bluecove_socket_LocalSocketImpl.h: No such file or dire            ctory
 #include "org_bluecove_socket_LocalSocketImpl.h"
                                                 ^
compilation terminated.

所以我需要修改 Makefile 以使其正确指向 .java 文件?我不太确定。

最佳答案

对于其他有同样问题的人。 由于某种原因,原始 make 文件无法与具有项目布局的现代 java 一起使用。 这会导致编译错误,导致无法生成 .class 文件。反过来,这意味着 Javah(从 Java 10 开始已弃用)在尝试为 native 库生成头文件以通过 JNI 进行通信时会失败。 c 编译器会忽略头文件的缺失并无论如何进行编译。这导致了一般链接器错误。该文件在那里,但 java 的 header 未包含在编译中。

为了解决这个问题,我在 Windows 系统上编译了 Bluecove-bluez jar,从 make 文件中删除了编译类以及清理目标,并直接将类从我的 Windows 系统复制到目标闪存驱动器编译。 将闪存驱动器移至 ARM Linux 系统,仅编译头文件和 c native 文件解决了该问题。

关于java - 在 ARM 上使用 BlueCove-DBus。 Linux 上 C 库和 Java 代码 (JNI) 之间的链接器错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51463010/

相关文章:

java - 如何将一个 EJB 3.1 注入(inject)另一个 EJB

java - 如何同时遍历两个 ArrayList?

c - Socket多线程实现C

php - 如何将 OCI8 安装到现有的 PHP?

linux - 如何在我的 bash PROMPT 中为当前的 git 分支添加颜色?

java - 从 JMenuItem java 打开一个弹出窗口

java - 何时调用 SecurityContextHolder.setContext()?

c - 警告 : Implicit declaration error

c - 2d矩阵分配函数segfault(参数返回的矩阵)

linux - Varnish 无法以 : failed to map segment from shared object: Operation not permitted 开头