使用arm-linux-gnueabi-gcc交叉编译链接.so库适配Android的问题
这个报错其实有点误导人——它说找不到./test,但你确认文件存在的话,本质问题是Android的动态链接器没法加载你的程序依赖的共享库,大概率是工具链兼容性和动态路径配置的问题,我给你一步步解决:
一、先搞懂核心问题:工具链不匹配
你用的arm-linux-gnueabi-gcc是给GNU/Linux ARM设备做的交叉工具链,而Android用的是自家的Bionic C库,不是GNU libc。这会导致两个致命问题:
- 程序可能依赖GNU libc专属的符号,Android根本没有
- 动态链接器路径不对:GNU/Linux用的是
/lib/ld-linux.so.3,Android用的是/system/bin/linker
所以最稳妥的方案是改用Android NDK提供的官方工具链,当然如果暂时不想换,我们也可以通过参数调整来适配。
二、现有工具链下的修复步骤
1. 重新编译共享库libfoo.so
加上ARM架构适配参数,同时检查未定义符号:
# 针对32位ARM设备(大部分旧Android设备)添加-march=armv7-a arm-linux-gnueabi-gcc -c -fPIC -march=armv7-a foo.c # --no-undefined提前检查是否有未定义符号,避免运行时踩坑 arm-linux-gnueabi-gcc -shared -o libfoo.so foo.o -Wl,--no-undefined
2. 编译test程序时指定动态链接器和运行时库路径
编译时必须告诉程序用Android的动态链接器,同时指定libfoo.so的存放路径(比如你打算传到Android的/data/local/tmp目录):
arm-linux-gnueabi-gcc -L/home/foo -o test main.c -lfoo \ -Wl,--dynamic-linker=/system/bin/linker \ -Wl,-rpath=/data/local/tmp
--dynamic-linker=/system/bin/linker:强制程序使用Android的动态链接器-Wl,-rpath=/data/local/tmp:设置程序运行时自动去这个路径找共享库
3. 上传文件并设置权限
把两个文件传到Android的/data/local/tmp(这个目录默认有读写执行权限):
# adb上传文件 adb push test /data/local/tmp/ adb push libfoo.so /data/local/tmp/ # 给执行权限 adb shell chmod +x /data/local/tmp/test /data/local/tmp/libfoo.so
然后运行测试:
adb shell cd /data/local/tmp && ./test
三、验证动态依赖是否正确
可以用readelf工具检查程序的动态配置是否生效:
arm-linux-gnueabi-readelf -d test
重点看这几个条目:
DT_INTERP:确认值是/system/bin/linkerDT_RPATH/DT_RUNPATH:确认路径是你设置的/data/local/tmpDT_NEEDED:确认包含libfoo.so
四、终极方案:改用Android NDK工具链
如果上面的方法还是有兼容性问题,直接用NDK的官方工具链最省心:
- 下载并解压Android NDK(比如r25版本)
- 调用工具链里的gcc(以32位ARM为例):
export NDK_PATH=~/android-ndk-r25 export CC=$NDK_PATH/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi19-gcc - 编译库和程序:
# 编译libfoo.so $CC -c -fPIC foo.c $CC -shared -o libfoo.so foo.o # 编译test程序 $CC -L/home/foo -o test main.c -lfoo -Wl,-rpath=/data/local/tmp
这样编译出来的程序完全适配Android的Bionic libc,不会有奇怪的兼容性问题。
内容的提问来源于stack exchange,提问作者Pineapple




