Android NDK - создание двух родных общих библиотек, вызывающих друг друга - программирование
Подтвердить что ты не робот

Android NDK - создание двух родных общих библиотек, вызывающих друг друга

Потеряно полдня, пытаясь построить две разделяемые библиотеки, например. mod1 и mod2 (которые Android NDK компилируется в libmod1.so и libmod2.so), из источников в jni-папке и вложенных папках, а затем mod1 вызывает функцию из mod2. Множество ответов о том, как сделать сборку, но тогда динамическая компоновка времени выполнения не работала, приложение разбилось при запуске.

Решил опубликовать этот вопрос и сразу ответить на него, чтобы Q и A ко всему процессу были вместе, и, надеюсь, кто-то еще не будет тратить впустую день, исследуя его снова.

4b9b3361

Ответ 1

Правильная процедура сборки была относительно простой, моя проблема заключалась в том, что создание libmod1.so зависело от libmod2.so вызвало неудовлетворенные ссылки при запуске - код mod1 не смог найти общую библиотеку mod2, хотя оба они были представлены в одной и той же папке в final APK, под libs/armeabi, libs/x86 и т.д. Однако, чтобы завершить мой ответ:

  • Поместите свои источники C или С++ и файлы заголовков в подкаталоги jni dir в проекте Android, например. папки mod1/и mod2/

  • В соответствии с инструкциями NDK создайте файл Application.mk, например. мой:

NDK_TOOLCHAIN_VERSION = 4,7
APP_PLATFORM: = android-8
APP_ABI: = armeabi armeabi-v7a x86

  • Создайте Android.mk, следуя этому шаблону:

LOCAL_PATH: = $(вызов my-dir)
включить $(CLEAR_VARS)
LOCAL_SHARED_LIBRARIES: = mod2   # это делает libmod1.so зависимым от libmod2.so
LOCAL_MODULE: = mod1
LOCAL_SRC_FILES: = mod1/file1.c
LOCAL_SRC_FILES + = mod1/file2.cpp
...
include $(BUILD_SHARED_LIBRARY)   # это фактически создает libmod1.so

включить $(CLEAR_VARS)
LOCAL_MODULE: = mod2
LOCAL_SRC_FILES: = mod2/file1.cc
LOCAL_SRC_FILES + = mod2/file2.cc
...
include $(BUILD_SHARED_LIBRARY)   # # это создает libmod2.so

Что об этом, все строит без жалоб с ndkbuild script. Для вызова некоторых функций из Java вам понадобится только оболочка C. И вот моя проблема. Поскольку у меня были функции, вызываемые из Java только в libmod1.so, мой класс оболочки C в Java был похож:

public class CWrapper {
    static {
        System.loadLibrary("mod1");
    }
    public static native int func1(String aParam);
    ...
}

Мне это казалось совершенно логичным - я вызываю libmod1.so из Java, поэтому я использовал System.loadLibrary( "mod1" ), а поскольку libmod1.so знает, что это зависит от libmod2.so, и оба файла находятся в в той же папке, libmod1 будет знать, как найти и загрузить libmod2, не так ли? Неправильно! Это сбой при запуске приложения с "неудовлетворенной ссылкой". Точное сообщение об ошибке:

java.lang.UnsatisfiedLinkError: Cannot load library: soinfo_link_image(linker.cpp:1635): could not load library "libmod2.so" needed by "libmod1.so"; caused by load_library(linker.cpp:745): library "libmod2.so" not found

Я искал везде, чтобы добавить еще один код для Android.mk, чтобы это было напрасно. Наконец, Эврика! Я изменил класс CWrapper следующим образом:

public class CWrapper {
    static {
        System.loadLibrary("mod2"); // must be first, as mod1 depends on mod2!
        System.loadLibrary("mod1");
    }
    public static native int func1(String aParam);
    ...
}

и все стало работать как шарм...

Грег