4

我正在尝试构建一个调用 C++ 后端的 android 应用程序。此后端使用 ZeroMQ 进行消息传递。根据 ZeroMQ 指南上的android 构建页面,我构建了一个 ndk 版本 6 的本机工具链,并使用它来(成功)构建 ZeroMQ。

但是,当我使用 JNI 实现构建自己的 .so 时,我似乎无法正确加载所有内容。具体来说,如果我调用System.LoadLibrary("zmq"),这将成功完成,但如果我随后调用 *System.LoadLibrary("my_lib")* 我总是收到 UnsatisfiedLinkError 抱怨:

Cannot load library reloc_library[1244]:   29 cannot locate zmq_msg_init'...

libmy_lib.so 已经生成了几种不同的方法,每种方法都没有成功。生成它后,我总是将 libmy_lib.so(以及 libzmq.so)复制到我的 android 项目的文件夹:libs/armeabi/。

# Compile all object files - this part was done for all options
/opt/android-toolchain/bin/arm-linux-androideabi-g++ -fpic -c Client_Events.cpp \
Client Wrapper.cpp jni.cpp -I /opt/android-root/include/ -I /my/project/specific/stuff

# Option 1 - Don't link the lib in at all
/opt/android-toolchain/bin/arm-linux-androideabi-g++ -shared  \
-Wl,-soname,libmy_lib.so -o libmy_lib.so jni.o Client_Events.o Client_Wrapper.o 

# Option 2 - Link ZeroMQ in statically
/opt/android-toolchain/bin/arm-linux-androideabi-g++ -shared  \
-Wl,-soname,libmy_lib.so -o libmy_lib.so jni.o Client_Events.o Client_Wrapper.o \
libzmq.a libstdc++.a -Wl,--whole-archive    

# Option 3 - Explicitly link ZeroMQ in dynamically
/opt/android-toolchain/bin/arm-linux-androideabi-g++ -shared  \
-Wl,-soname,libmy_lib.so -o libmy_lib.so jni.o Client_Events.o Client_Wrapper.o \
-L /opt/android-root/lib/ -lzmq

对于这些选项中的每一个,我都尝试在加载我自己的库之前显式调用System.LoadLibrary("zmq")而不是。结果没有任何变化。使用 nm 可以确认,至少在选项 #2 的情况下,缺少的符号 *zmq_msg_init* 确实存在于 libmy_lib.so 中。

关于为什么找不到链接的 ZeroMQ 符号的任何想法?

4

1 回答 1

14

我刚刚学会了如何编译第二个库并将其链接到我在 android ndk 中的主库。让我看看我对你有没有用。

以下是我如何创建我的第二个库(在我的例子中,我将子弹物理库和 irrlicht 渲染引擎构建为我的游戏的 2 个单独的库)。

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_C_INCLUDES := HEADER FILES 
LOCAL_MODULE := bullet
LOCAL_SRC_FILES := SRC FILES

LOCAL_ARM_MODE := arm
LOCAL_CFLAGS := $(LOCAL_C_INCLUDES:%=-I%) -O3 -DANDROID_NDK -DDISABLE_IMPORTGL
LOCAL_LDLIBS := -ldl -llog

include $(BUILD_SHARED_LIBRARY)

然后将您的 libxxxx.so(在我的情况下为 libbullet.so 和 libirrlicht.so)复制到您的 jni 文件夹。并在您的主库 .mk 文件中添加以下内容。

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_C_INCLUDES := (includes for bullet)
LOCAL_MODULE := bullet
LOCAL_SRC_FILES := libbullet.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_C_INCLUDES := (includes for irrlicht)
LOCAL_MODULE := irrlicht
LOCAL_SRC_FILES := libirrlicht.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)

LOCAL_C_INCLUDES := (includes for bullet + includes for irrlicht + includes for main code)
LOCAL_SRC_FILES := main code src files

LOCAL_MODULE := gamescript

LOCAL_ARM_MODE   := arm
LOCAL_CFLAGS := $(LOCAL_C_INCLUDES:%=-I%) -O3 -DANDROID_NDK -DDISABLE_IMPORTGL
LOCAL_LDLIBS := -lOpenSLES -landroid -ldl -llog

LOCAL_SHARED_LIBRARIES := bullet irrlicht

include $(BUILD_SHARED_LIBRARY)

现在,以正确的顺序将所有库添加到您的 java 代码中。

System.loadLibrary("bullet");
System.loadLibrary("irrlicht");
System.loadLibrary("gamescript");
于 2012-05-16T09:33:21.627 回答