使用android ndk

时间:2018-02-13 06:17:18

标签: android-ndk java-native-interface android-shell

我正在尝试构建一个可执行文件,它依赖于C中用于android的共享库。我想在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

然后在运行$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工作,就不知道我该怎么做。

2 个答案:

答案 0 :(得分:1)

库未正确构建。 SONAME路径is not new存在此类问题。它已在API 23中的Android中的一个特定fix之后浮出水面。

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

答案 1 :(得分:0)

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

在运行 $ 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测试一样,我得到了另一个字段(当时可执行文件工作时不太关心它)

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