Невозможно запустить исполняемый файл с использованием предварительно созданной общей библиотеки с помощью 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 было добавлено

Другие вопросы по тегам