无法使用 android ndk 使用预构建的共享库执行 运行 可执行文件

Cannot run executable using a prebuilt shared library using android ndk

我正在尝试为 android 构建依赖于 C 中的共享库的可执行文件。我想 运行 android shell 上的可执行文件。 我首先使用 android ndk(我正在使用 android-ndk-r16b)构建可执行文件,然后使用 adb push 我将 ndk 生成的文件放在我的 android 设备然后使用 adb shell 我尝试 运行 可执行文件。

我正在构建 Ubuntu 14.04。 我使用 apt-get:

安装了 android arm 工具链
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);

生成文件:

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

然后 运行ning $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 # 

为什么它 link 指向我的笔记本电脑的路径?

如果有人能告诉我我做错了什么或就他们如何做类似的事情给我建议,我将不胜感激。

我的实际任务需要 link 更复杂的共享库和 运行 android shell 上的可执行文件。如果我能得到一个简单的 .so 工作,我不知道我将如何做到这一点。

库未正确构建。这种 SONAME 路径 is not new. It has surfaced after one particular fix in Android at API 23.

的问题

如果出于某种原因您无法使用最新的 NDK 重建此库,您可以尝试使用 patchelf 实用程序将 SONAME 添加到现有二进制文件中。

我尝试了 Alex Cohen 指定的方法之一。

On 运行 $readelf -d test 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 test 更改库名称后,我得到了另一个字段(由于可执行文件的工作,目前不太在意它)

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