Невозможно запустить исполняемый файл с использованием предварительно созданной общей библиотеки с помощью Android ndk
Я пытаюсь построить исполняемый файл, который зависит от общей библиотеки в C для Android. Я хочу запустить исполняемый файл на оболочке Android. Сначала я собрал исполняемый файл с помощью android ndk (я использую android-ndk-r16b), затем с помощью adb push я поместил файлы, сгенерированные ndk, на свое устройство Android, а затем с помощью оболочки adb попытался запустить исполняемый файл.
Я строю на Ubuntu 14.04. Я установил набор инструментов для Android с помощью apt-get
:
sudo apt-get install gcc-arm-linux-androideabi
Вот мои файлы:
Общая библиотека: libcal.so
cal.c:
#include "cal.h"
int add(int a , int b)
{
return (a + b);
}
int sub(int a, int b)
{
return (a - b);
}
cal.h:
int add(int a , int b);
int sub(int a, int b);
Makefile:
CXX=arm-linux-androideabi-gcc
CXXFLAGS=-fPIC -Wall -I. -c
LDFLAGS=-shared
SOURCES=./cal.c
OBJECTS=$(SOURCES:.c=.o)
TARGET_LIB=libcal.so
all: $(SOURCES) $(TARGET_LIB)
$(TARGET_LIB): $(OBJECTS)
$(CXX) -o $@ $(OBJECTS) $(LDFLAGS)
.c.o:
$(CXX) $(CXXFLAGS) $< -o $@
.PHONY: clean
clean:
@rm -f $(TARGET_LIB) $(OBJECTS)
Так вот, как я генерирую общую библиотеку. Затем в папке с именем jni у меня есть следующие файлы:
test.c:
#include <stdio.h>
#include "cal.h"
int main()
{
int sum = 0, diff = 0;
sum = add(3,2);
diff = sub(2,2);
printf("sum = %d\ndiff = %d\n",sum, diff);
return 0;
}
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := cal
LOCAL_SRC_FILES := $(LOCAL_PATH)/../../library/libcal.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/../../library/
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := test
LOCAL_SRC_FILES := test.c
LOCAL_SHARED_LIBRARIES := cal
include $(BUILD_EXECUTABLE)
Application.mk
APP_ABI := armeabi-v7a
APP_PLATFORM := android-19
Потом на бег $ndk-build
это мой вывод
rohith@rohith-Lenovo-G50-80:~/example2/hello/jni$ ndk-build
[armeabi-v7a] Prebuilt : libcal.so <= jni/../../library/
[armeabi-v7a] Install : libcal.so => libs/armeabi-v7a/libcal.so
[armeabi-v7a] Compile thumb : test <= test.c
[armeabi-v7a] Executable : test
[armeabi-v7a] Install : test => libs/armeabi-v7a/test
rohith@rohith-Lenovo-G50-80:~/example2/hello/jni$ cd ../libs/armeabi-v7a/
rohith@rohith-Lenovo-G50-80:~/example2/hello/libs/armeabi-v7a$ ls
libcal.so test
rohith@rohith-Lenovo-G50-80:~/example2/hello/libs/armeabi-v7a$
Таким образом, мои совместимые с Android файлы находятся в папке libs
ПРИМЕЧАНИЕ. Если я не использую Application.mk, сборка завершится неудачно со следующим выводом
rohith@rohith-Lenovo-G50-80:~/example/hello/jni$ ndk-build
Android NDK: APP_PLATFORM not set. Defaulting to minimum supported version android-14.
[arm64-v8a] Prebuilt : libcal.so <= jni/../../library/
[arm64-v8a] Install : libcal.so => libs/arm64-v8a/libcal.so
[arm64-v8a] Compile : test <= test.c
[arm64-v8a] Executable : test
/home/rohith/example/hello/obj/local/arm64-v8a/libcal.so: error adding symbols: File in wrong format
clang++: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [/home/rohith/example/hello/obj/local/arm64-v8a/test] Error 1
В любом случае, теперь, после того, как я поместил общую библиотеку и исполняемый файл на устройство Android и запустил исполняемый файл, я получаю следующую ошибку:
rohith@rohith-Lenovo-G50-80:~/example2/hello/libs/armeabi-v7a$ ls
libcal.so test
rohith@rohith-Lenovo-G50-80:~/example2/hello/libs/armeabi-v7a$ cd ..
rohith@rohith-Lenovo-G50-80:~/example2/hello/libs$ adb push armeabi-v7a /data/local/rohith
push: armeabi-v7a/libcal.so -> /data/local/rohith/libcal.so
push: armeabi-v7a/test -> /data/local/rohith/test
2 files pushed. 0 files skipped.
134 KB/s (11088 bytes in 0.080s)
rohitht@rohith-Lenovo-G50-80:~/example2/hello/libs$ adb shell
root@tcc897x:/ # cd /data/local/rohith
root@tcc897x:/data/local/rohith # ls
libcal.so
test
root@tcc897x:/data/local/rohith # export LD_LIBRARY_PATH=.
root@tcc897x:/data/local/rohith # ./test
CANNOT LINK EXECUTABLE: could not load library "/home/rohith/example2/hello/obj/local/armeabi-v7a/libcal.so" needed by "./test"; caused by library "/home/rohith/example2/hello/obj/local/armeabi-v7a/libcal.so" not found
1|root@tcc897x:/data/local/rohith #
Почему это связано с путями относительно моего ноутбука?
Я был бы очень признателен, если бы кто-то мог сказать, что я делаю неправильно, или дать мне совет о том, как они поступили так же.
Моя реальная задача требует, чтобы я связывал гораздо более сложные разделяемые библиотеки и запускал исполняемый файл на оболочке Android. Не знаю, как я это сделаю, если смогу получить простую работу.
2 ответа
Библиотека была построена неправильно. Такая проблема с SONAME не нова. Он появился после одного конкретного исправления в Android на API 23.
Если по какой-либо причине вы не можете перестроить эту библиотеку с последним NDK, вы можете попробовать утилиту patchelf, чтобы добавить SONAME в существующий двоичный файл.
Я попробовал один из методов, указанных Алексом Коэном.
При запуске теста $readelf -d для исполняемого файла, сгенерированного NDK, вывод будет следующим:
(...)
0x00000004 (HASH) 0x41c
0x00000001 (NEEDED) Shared library: [/home/rohith/example2/hello/obj/local/armeabi-v7a/libcal.so]
0x00000001 (NEEDED) Shared library: [libc.so]
0x00000001 (NEEDED) Shared library: [libm.so]
0x00000001 (NEEDED) Shared library: [libstdc++.so]
0x00000001 (NEEDED) Shared library: [libdl.so]
(...)
Путь к общей библиотеке добавляется к ее имени. Таким образом, чтобы изменить это на libcal.so, я использовал patchelf.
Вот команды, которые я использовал:
$patchelf --remove-needed /home/rohith/example2/hello/obj/local/armeabi-v7a/libcal.so test
$patchelf --add-needed libcal.so test
Примечание: это не может быть идеальным решением. Как и при запуске теста readelf -d после изменения имен библиотек, я получил еще одно поле (на данный момент не слишком беспокоит, так как исполняемый файл работает)
rohith@rohith-Lenovo-G50-80:~/example2/hello/libs/armeabi-v7a$ readelf -d test
Dynamic section at offset 0x4000 contains 32 entries:
Tag Type Name/Value
0x00000001 (NEEDED) Shared library: [libcal.so]
0x0000001d (RUNPATH) Library runpath: [/home/rohith/example2/hello/obj/local/armeabi-v7a/libcal.so:./libcal.so]
0x00000003 (PLTGOT) 0x2fcc
0x00000002 (PLTRELSZ) 80 (bytes)
0x00000017 (JMPREL) 0x50c
0x00000014 (PLTREL) REL
0x00000011 (REL) 0x4ac
0x00000012 (RELSZ) 96 (bytes)
0x00000013 (RELENT) 8 (bytes)
0x6ffffffa (RELCOUNT) 10
0x00000015 (DEBUG) 0x0
0x00000006 (SYMTAB) 0x224
0x0000000b (SYMENT) 16 (bytes)
0x00000005 (STRTAB) 0x4130
0x0000000a (STRSZ) 347 (bytes)
0x00000004 (HASH) 0x41c
0x00000001 (NEEDED) Shared library: [libc.so]
0x00000001 (NEEDED) Shared library: [libm.so]
Это дополнительное поле типа RUNPATH было добавлено