Я пишу приложение для Android, которое хочет сделать вызовы JNI в общую библиотеку, созданную с использованием NDK. Фокус в том, что это общие функции вызовов библиотеки, предоставляемые ДРУГИМИ разделяемыми библиотеками. Другие общие библиотеки - это библиотеки C, которые были скомпилированы в другом месте.
Вот что я пробовал:
Моя среда: Я работаю в Eclipse. Я добавил собственную поддержку и имею библиотеку jni. В этой библиотеке у меня есть мой код и каталог \lib, где я скопировал другие .so файлы.
Попытка # 1 Android.mk: просто сообщите, где находятся
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := native_lib
LOCAL_SRC_FILES := native_lib.cpp
LOCAL_LDLIBS := -L$(SYSROOT)/../usr/lib -llog
LOCAL_LDLIBS += -L$(LOCAL_PATH)/lib/support_lib1
LOCAL_LDLIBS += -L$(LOCAL_PATH)/lib/support_lib2
include $(BUILD_SHARED_LIBRARY)
Это просто отлично, но когда я пытаюсь запустить, я получаю ошибки, указывающие на то, что dlopen (libnative_lib) не удалось, потому что он не мог загрузить libsupport_lib1.
Придя сюда, я нашел это:
Может ли общая библиотека вызывать другую разделяемую библиотеку?
в котором говорилось, что мне нужно вызвать библиотеку загрузки для всех необходимых библиотек. Отлично!
Попытка # 2 Открытие каждой библиотеки сначала
static {
System.loadLibrary("support_lib1");
System.loadLibrary("support_lib2");
System.loadLibrary("native_lib");
}
Опять же, это просто отлично, но когда я запускаю, я получаю новую ошибку:
не удалось загрузить libsupport_lib1. findLibrary возвращается null.
Теперь мы куда-то добираемся. Он не должен загружать библиотеки в цель.
Попытка # 3 Копирование .so файлов в проект /libs/armeabi
Не работает. Когда Eclipse создает, он удаляет файлы, которые я туда запустил.
Попытка # 4 Создание нового модуля для каждой библиотеки
Итак, я нашел это:
Android NDK: ссылка с использованием предварительно скомпилированной статической библиотеки
Это о статических библиотеках, но, возможно, у меня такая же проблема. Суть в том, что мне нужно объявить модуль для каждой библиотеки. Итак, мой новый Android.mk выглядит так:
LOCAL_PATH := $(call my-dir)
#get support_lib1
include $(CLEAR_VARS)
LOCAL_MODULE := support_lib1
LOCAL_SRC_FILES := $(LOCAL_PATH)/lib/support_lib1.so
include $(BUILD_SHARED_LIBRARY)
#get support_lib2
include $(CLEAR_VARS)
LOCAL_MODULE := support_lib2
LOCAL_SRC_FILES := $(LOCAL_PATH)/lib/support_lib2.so
include $(BUILD_SHARED_LIBRARY)
#build native lib
include $(CLEAR_VARS)
LOCAL_MODULE := native_lib
LOCAL_SRC_FILES := native_lib.cpp
LOCAL_LDLIBS := -L$(SYSROOT)/../usr/lib -llog
LOCAL_LDLIBS += -L$(LOCAL_PATH)/lib/support_lib1
LOCAL_LDLIBS += -L$(LOCAL_PATH)/lib/support_lib2
include $(BUILD_SHARED_LIBRARY)
Это строит! Еще лучше, теперь армеаби имеет sos! Даже ЛУЧШЕ Я получаю следующие сообщения, когда я пытаюсь запустить его (говоря мне, что support_lib1 и 2 были открыты LoadLibrary:
Попытка загрузить lib/data/app-lib/com.example.tst/libsupport_lib1.so добавлен общий файл lib/data/app-lib/com.example.tst/libsupport_lib1.so нет JNI_OnLoad найдено в /data/app -lib/com.example.tst/libsupport_lib1.so, пропущен init
но затем... dlopen не удалось: не удалось найти символ func_that_exists_in_libsupport_lib.so, на который ссылается libnative_lib.so
Изменить: Попытка 5: Использовать PREBUILT_SHARED_LIBRARY
Итак, я нашел это: Как я могу связать предварительно созданную общую библиотеку с проектом NDK для Android?
который, кажется, именно то, что я прошу. Их ответ кажется "не использовать" build_shared_library ", но вместо этого" используйте PREBUILT_SHARED_LIBRARY
Хорошо, пусть попробует.
LOCAL_PATH := $(call my-dir)
#get support_lib1
include $(CLEAR_VARS)
LOCAL_MODULE := support_lib1
LOCAL_SRC_FILES := $(LOCAL_PATH)/lib/support_lib1.so
include $(PREBUILT_SHARED_LIBRARY)
#get support_lib2
include $(CLEAR_VARS)
LOCAL_MODULE := support_lib2
LOCAL_SRC_FILES := $(LOCAL_PATH)/lib/support_lib2.so
include $(PREBUILT_SHARED_LIBRARY)
#build native lib
include $(CLEAR_VARS)
LOCAL_MODULE := native_lib
LOCAL_SRC_FILES := native_lib.cpp
LOCAL_LDLIBS := -L$(SYSROOT)/../usr/lib -llog
LOCAL_SHARED_LIBRARIES := support_lib1 support_lib2
include $(BUILD_SHARED_LIBRARY)
Построить... не удается! Теперь сборка жалуется на отсутствие символов.
Изменить: Попытка 6: Сгладить все
Итак, я вернулся к документации по предварительным загрузкам в NDK. В нем говорится:
Каждая предварительно построенная библиотека должна быть объявлена как отдельный независимый модуль для системы сборки. Вот тривиальный пример, где мы предполагаем, что файл "libfoo.so" находится в том же каталоге, что и Android.mk ниже:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := foo-prebuilt
LOCAL_SRC_FILES := libfoo.so
include $(PREBUILT_SHARED_LIBRARY)
Обратите внимание, что для объявления такого модуля вам действительно нужно только следующее:
Дайте модулю имя (здесь "foo-prebuilt" ). Это не обязательно должно соответствовать имени самой предварительно созданной библиотеки.
Назначьте LOCAL_SRC_FILES путь к предварительно созданной библиотеке, которую вы предоставляете. Как обычно, путь относится к вашему LOCAL_PATH.
Включите PREBUILT_SHARED_LIBRARY, а не BUILD_SHARED_LIBRARY, если вы предоставляете общую библиотеку. Для статических используйте PREBUILT_STATIC_LIBRARY. Предварительно построенный модуль ничего не создает. Однако копия вашей предварительно созданной общей библиотеки будет скопирована в $PROJECT/obj/local, а другая будет скопирована и разделена на $PROJECT/libs/.
Итак, попробуйте сгладить все, чтобы соответствовать тривиальному примеру. Я скопировал свои библиотеки из их удобной папки /lib и поместил их в jni-root. Затем я сделал следующее:
LOCAL_PATH := $(call my-dir)
#get support_lib1
include $(CLEAR_VARS)
LOCAL_MODULE := support_lib1
LOCAL_SRC_FILES := support_lib1.so
include $(PREBUILT_SHARED_LIBRARY)
#get support_lib2
include $(CLEAR_VARS)
LOCAL_MODULE := support_lib2
LOCAL_SRC_FILES := support_lib2.so
include $(PREBUILT_SHARED_LIBRARY)
#build native lib
include $(CLEAR_VARS)
LOCAL_MODULE := native_lib
LOCAL_SRC_FILES := native_lib.cpp
LOCAL_LDLIBS := -L$(SYSROOT)/../usr/lib -llog
LOCAL_SHARED_LIBRARIES := support_lib1 support_lib2
include $(BUILD_SHARED_LIBRARY)
и... такая же ошибка. Более того, я определенно НЕ вижу, что файлы библиотек копируются в $PROJECT/obj/local.
sooooo.... теперь что?