Android NDK - создайте две собственные разделяемые библиотеки, вызывающие друг друга
Потратил полдня на сборку двух общих библиотек, например mod1
а также mod2
(из которого Android NDK компилируется в libmod1.so
а также libmod2.so
), из источников в папке jni и подпапках, затем вызовите функцию mod1 из mod2. Множество ответов о том, как заставить сборку работать, но динамическое связывание во время выполнения не работало, приложение зависало при запуске.
Решил опубликовать этот вопрос и сразу же ответить на него, чтобы Q и A во всем процессе были вместе, и, надеюсь, кто-то еще не потратит впустую день, исследуя его снова.
1 ответ
Правильная процедура сборки была относительно простой, моя проблема заключалась в том, что из-за того, что libmod1.so зависел от libmod2.so, вызывал неудовлетворенные ссылки при запуске - коду mod1 не удалось найти общую библиотеку mod2, даже несмотря на то, что обе они присутствовали в одной папке в конечном APK, под libs/armeabi, libs/x86 и т. д. Однако, чтобы завершить мой ответ:
Поместите исходные тексты C или 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: = $ (позвоните в мой каталог)
включает $ (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. Вам нужна только оболочка C для вызова некоторых функций из Java. И здесь была моя проблема. Так как у меня были функции, вызываемые из 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);
...
}
и все стало работать как шарм...
Greg