Android NDK:使用的静态库与指定的预编译库不同

Android NDK: Static library used is different than precompiled library specified

本文关键字:编译 NDK 静态 Android      更新时间:2023-10-16

我使用Android SDK编译器手动构建了一个C++库。结果是libMyUtils.a.

我在Java/JNI测试应用程序中使用以下内容:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE    := MyUtils
LOCAL_SRC_FILES := ../../../../libs/libMyUtils.a
include $(PREBUILT_STATIC_LIBRARY)
LOCAL_MODULE    := AndroidTests
LOCAL_STATIC_LIBRARIES    := MyUtils
include $(BUILD_SHARED_LIBRARY)

当我构建控制台时,显示以下内容:

[armeabi] Install        : libMyUtils.so => libs/armeabi/libMyUtils.so

现在由于某种奇怪的原因图书馆../../..//libs/libMyUtils.a是几兆字节,但库libs/armeabi/libMyUtil.so只有5KB。它不应该是同一个图书馆吗?

当我运行我的测试应用程序时,我会得到不满意的链接错误。很明显,我调用的本机函数不在库中。我做错了什么?

一个完整的解释,因为你的Android.mk对我来说没有多大意义:对不起,如果你已经知道其中的一些。

静态库应该是纯C/C++,并使用AndroidNDK进行封装,以便从Java中使用。

例如,假设您的静态库是从一个简单的.c和.h文件构建的:

高音。h:

int giveMeFive();

高音。c:

#include "highfive.h"
int giveMeFive() {
  return 5;
}

可以使用Android NDK编译器将其编译为静态库,显然您已经知道如何做到这一点:这将为我们提供一个highfive.a库。

在这种形式下,这个库在Java中是不可用的,但它可以使用Android NDK进行封装。有关命名约定等,请参阅Android NDK文档

highfiveWrapper.c:

#include "highfive.h"
jint
Java_your_package_name_HighFive_giveMeFive(JNIEnv *env, jobject o) {
  return (jint) giveMeFive();
}

及其对应的Java文件:

package your.package.name;
class HighFive {
  static {
    System.loadLibrary("highfive");
  }
  public native int giveMeFive();
}

现在,我们如何编译所有这些以使其发挥作用:

Android.mk:

include $(CLEAR_VARS)
LOCAL_MODULE            := libhighfive-prebuilt
LOCAL_SRC_FILES         := path/to/highfive.a
LOCAL_EXPORT_C_INCLUDES := path/to/highfive.h/folder
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE      := highfive
LOCAL_SRC_FILES   := path/to/highfiveWrapper.c
LOCAL_STATIC_LIBRARIES := libhighfive-prebuilt
include $(BUILD_SHARED_LIBRARY)

在那里,你应该可以随心所欲地使用你的本地图书馆!

希望这能有所帮助!

通常,静态库包含许多对象,这些对象包含许多函数,其中许多函数是未使用的。这就是为什么链接器只从静态库中提取引用的对象。因此,在@mbrenon给出的例子中,highfiveWrapper.c定义了highfive.a的哪些组件将链接到highfive.so中。

但在您的设置中,您需要加载整个静态库。好的,这里有一个特殊的词:LOCAL_WHOLE_STATIC_LIBRARIES。

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE    := MyUtils
LOCAL_SRC_FILES := ../../../../libs/libMyUtils.a
include $(PREBUILT_STATIC_LIBRARY)
LOCAL_MODULE    := AndroidTests
LOCAL_WHOLE_STATIC_LIBRARIES    := MyUtils
include $(BUILD_SHARED_LIBRARY)

最终,解决方案是将MyUtils库构建为预构建的共享库。这样链接器就不会剥离任何内容。然后我修改了我的makefile如下:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE    := MyUtils
LOCAL_SRC_FILES := ../../../../libs/libMyUtils.so
include $(PREBUILT_SHARED_LIBRARY)
LOCAL_MODULE    := AndroidTests
LOCAL_SHARED_LIBRARIES    := MyUtils
include $(BUILD_SHARED_LIBRARY)

请注意.so扩展和PREBUILT_SHARED_LIBRARY和BUILD_SHAREDLIBRARY脚本。