我正在尝试构建一个可执行文件,它依赖于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工作,就不知道我该怎么做。答案 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