0

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

我在 Ubuntu 14.04 上构建。我使用以下方法安装了 android arm 工具链apt-get

sudo apt-get install gcc-arm-linux-androideabi

这是我的文件:

共享库:libcal.so

计算:

#include "cal.h"
int add(int a , int b)
{
    return (a + b);
}
int sub(int a, int b)
{
    return (a - b);
}

卡路里:

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 的文件夹中,我有以下文件:

测试.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;
} 

安卓.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)    

应用程序.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 shell 上运行可执行文件。如果我能得到一个简单的 .so 工作,我不知道该怎么做。

4

2 回答 2

1

该库未正确构建。SONAME 路径的这种问题并不新鲜。它在 Android 的 API 23 中的一个特定修复后浮出水面。

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

于 2018-02-13T09:11:19.427 回答
0

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

在对 NDK 生成的可执行文件运行$readelf -d test时,输出如下:

(...)
 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

于 2018-02-13T11:37:36.773 回答