Android64位库编译遇到的问题和处理方法
小舟从此逝,江海度余生
Android64位库适配的必要性
随着处理器的升级换代,64位处理器渗透到更多的行业,在手机很通用的64位处理器,在安防领域逐渐扩大开来,同行业的厂商的sdk逐渐开始支持64位,这对于我们设备开发者来讲,如果没有任何一个库使用的是64位的话,还可以在应用的兼容模式下跑32位的库,但是很不巧,遇到了一个厂商只能提供64位的库,要使用他的功能就必须把所有的库都转化成64位,而对于使用大量32位库的老项目来讲,这是一个工作量巨大的事情,所以还在使用32位库的项目尽早适配64位吧
Android64位库编译需要的环境
ubuntu系统(也可以是windows ndk环境,windows下最大的问题就是需要自己写Android.mk, 以及处理源码结构)
ndk下载并解压 (根据系统来下对应的ndk版本,建议使用比较通用的版本,比如ndk 14e,如果用太新的,可能会出现各种意想不到问题)
https://github.com/android/ndk/wiki/Unsupported-Downloads
源码,尽量使用通用的源码(通用,采坑的人多,遇到问题也容易找到答案)
一个列子:openssl库
为了便于说明问题,以openssl为列,编译一个库,抛转引玉
第一步下载源码,解压
git clone git://git.openssl.org/openssl.git
第二步配置编译选项
./Configure linux-aarch64 --cross-compile-prefix=aarch64-linux-gnu-
root@software-wrt:/home/yuehy/test# file /usr/local/lib/libssl.so.3
/usr/local/lib/libssl.so.3: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, BuildID[sha1]=00c552de16d1f6b4bb314073353e27b92a90cd57, not stripped
单纯从信息来看 ARM aarch64 是arm64位
但问题在于,链接的库都不是Android的库
~/test$ readelf -d /usr/local/lib/libssl.so.3
Dynamic section at offset 0x8fbd0 contains 33 entries:
标记 类型 名称/值
0x0000000000000001 (NEEDED) 共享库:[libcrypto.so.3]
0x0000000000000001 (NEEDED) 共享库:[libpthread.so.0]
0x0000000000000001 (NEEDED) 共享库:[libc.so.6]
0x0000000000000001 (NEEDED) 共享库:[ld-linux-aarch64.so.1]
0x000000000000000e (SONAME) Library soname: [libssl.so.3]
但是从链接信息来看链接是带有版本号的库,这种链接库在Android应用里面是没办法找到的,所以这种库是没办法在Android里面使用的
正确的库,使用的是Android系统的链接库,正确的编译姿势是,使用ndk里面Android64位对应的编译器,链接Android64位的基础库,使用64位Android的头文件
附上正确的编译语句
CPPFLAGS="-I/usr/local/android-ndk-r14b/platforms/android-21/arch-arm64/usr/include" LDFLAGS="-Wl,-rpath-link=/usr/local/android-ndk-r14b/platforms/android-21/arch-arm64/usr/lib -L/usr/local/android-ndk-r14b/platforms/android-21/arch-arm64/usr/lib" LIBS="-ldl" ./Configure linux-aarch64 --cross-compile-prefix=/usr/local/android-ndk-r14b/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android- --prefix=/home/yuehy/test/openssl/out no-asm shared no-async
说明
CPPFLAGS :一般是加载头文件的路径 同 --extra-cflags
LDFLAGS :一般是库的链接路径 如-Wl,-rpath-link= 是配置优先链接库路径 编译的部分选项也可以在这里配置 如-shared -fPIC -DPIC 等 同--extra-ldflags
--sysroot= 一般是ndk的sysroot目录
--cross-compile-prefix:一般是编译使用的通用头,如本列中使用的--cross-compile-prefix=/usr/local/android-ndk-r14b/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-
系统编译的时候会自动加上gcc,g++,clang等,完整的路径会是这样/usr/local/android-ndk-r14b/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-gcc
**--host=aarch64-linux-gnu **
**--target-os=android **
**--arch=aarch64 **
配置编译的目标系统
**配置soname -Wl,-soname -Wl,libsqlite3.so **
--prefix=/home/out 配置生成文件的输出路径
--enable-cross-compile 开启交叉编译
第三步 编译
make
可能会遇到如下问题
engines/dasync-dso-e_dasync.o: In function `dasync_aes128_cbc_hmac_sha1_ctrl':
e_dasync.c:(.text+0x2c0): undefined reference to `memcpy'
engines/dasync-dso-e_dasync.o: In function `wait_cleanup':
e_dasync.c:(.text+0x568): undefined reference to `close'
e_dasync.c:(.text+0x570): undefined reference to `close'
engines/dasync-dso-e_dasync.o: In function `dasync_aes128_cbc_ctrl':
e_dasync.c:(.text+0x13ec): undefined reference to `memcpy'
engines/dasync-dso-e_dasync.o: In function `dummy_pause_job':
e_dasync.c:(.text+0x14a8): undefined reference to `write'
e_dasync.c:(.text+0x14c0): undefined reference to `read'
e_dasync.c:(.text+0x14f8): undefined reference to `pipe'
e_dasync.c:(.text+0x1550): undefined reference to `close'
e_dasync.c:(.text+0x1558): undefined reference to `close'
engines/dasync-dso-e_dasync.o: In function `bind_engine':
e_dasync.c:(.text+0x1694): undefined reference to `strcmp'
collect2: error: ld returned 1 exit status
Makefile:21363: recipe for target 'engines/dasync.so' failed
make[1]: *** [engines/dasync.so] Error 1
make[1]: Leaving directory '/home/yuehy/test/openssl'
Makefile:3277: recipe for target 'build_sw' failed
make: *** [build_sw] Error 2
在编译的标志里面去掉 nostdlib 去掉-D__ANDROID_API__=21 就可以正常编译通过
编译中遇到的问题,一般来说如下几个方面检查
1. 头文件路径不正确导致
2. 库的链接路径不对
3. 编译的附加选项配置不正确 如nostdlib -ldl之类
4. 如果前三步没问题,那你遇见的的问题就是大家都会遇见的问题,建议谷歌
第四步,库的名称问题
生成的库名字叫libssl.so.3 ,这倒是可以改,但是
0x000000000000000e (SONAME) Library soname: [libssl.so.3]
soname是连接库的时候的标识,而Android是不认这种带版本号的库的
解决方法:修改Makefile的选项
#SHLIBS=libcrypto.so.3 libssl.so.3
SHLIBS=libcrypto.so libssl.so
#SHLIB_INFO="libcrypto.so.3;libcrypto.so;" "libssl.so.3;libssl.so;"
SHLIB_INFO="libcrypto.so;libcrypto.so;" "libssl.so;libssl.so;"
$(CC) $(LIB_CFLAGS) -L. $(LIB_LDFLAGS) -Wl,-soname=libssl.so \
-o libssl.so -Wl,--version-script=libssl.ld \
#libssl.so: libssl.so.3
# rm -f libssl.so && \
# ln -s libssl.so.3 libssl.so
libssl.so: crypto/libssl-shlib-packet.o ssl/libssl-shlib-bio_ssl.o \
ssl/libssl-shlib-d1_lib.o ssl/libssl-shlib-d1_msg.o \
ssl/libssl-shlib-d1_srtp.o ssl/libssl-shlib-methods.o \
ssl/libssl-shlib-pqueue.o ssl/libssl-shlib-s3_cbc.o \
ssl/libssl-shlib-s3_enc.o ssl/libssl-shlib-s3_lib.o \
ssl/libssl-shlib-s3_msg.o ssl/libssl-shlib-ssl_asn1.o \
ssl/libssl-shlib-ssl_cert.o ssl/libssl-shlib-ssl_ciph.o \
ssl/libssl-shlib-ssl_conf.o ssl/libssl-shlib-ssl_err.o \
ssl/libssl-shlib-ssl_err_legacy.o ssl/libssl-shlib-ssl_init.o \
ssl/libssl-shlib-ssl_lib.o ssl/libssl-shlib-ssl_mcnf.o \
ssl/libssl-shlib-ssl_rsa.o ssl/libssl-shlib-ssl_rsa_legacy.o \
ssl/libssl-shlib-ssl_sess.o ssl/libssl-shlib-ssl_stat.o \
ssl/libssl-shlib-ssl_txt.o ssl/libssl-shlib-ssl_utst.o \
ssl/libssl-shlib-t1_enc.o ssl/libssl-shlib-t1_lib.o \
ssl/libssl-shlib-t1_trce.o ssl/libssl-shlib-tls13_enc.o \
ssl/libssl-shlib-tls_depr.o ssl/libssl-shlib-tls_srp.o \
ssl/record/libssl-shlib-dtls1_bitmap.o \
ssl/record/libssl-shlib-rec_layer_d1.o \
ssl/record/libssl-shlib-rec_layer_s3.o \
ssl/record/libssl-shlib-ssl3_buffer.o \
ssl/record/libssl-shlib-ssl3_record.o \
ssl/record/libssl-shlib-ssl3_record_tls13.o \
ssl/record/libssl-shlib-tls_pad.o \
ssl/statem/libssl-shlib-extensions.o \
ssl/statem/libssl-shlib-extensions_clnt.o \
修改所有的libcrypto.so.3 为libcrypto.so
~/test/openssl$ readelf -d libssl.so
Dynamic section at offset 0x87c68 contains 30 entries:
标记 类型 名称/值
0x0000000000000001 (NEEDED) 共享库:[libcrypto.so]
0x0000000000000001 (NEEDED) 共享库:[libdl.so]
0x0000000000000001 (NEEDED) 共享库:[libc.so]
0x000000000000000e (SONAME) Library soname: [libssl.so]
现在就是一个可以正常使用的Android库了
编译curl Android64位库
编译指令
CPPFLAGS="-I/usr/local/android-ndk-r14b/platforms/android-21/arch-arm64/usr/include" LDFLAGS="-Wl,-rpath-link=/usr/local/android-ndk-r14b/platforms/android-21/arch-arm64/usr/lib -L/usr/local/android-ndk-r14b/platforms/android-21/arch-arm64/usr/lib" LIBS="-ldl" CC=/usr/local/android-ndk-r14b/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-gcc ./configure --target=aarch64-linux-gnu --host=aarch64-linux-gnu --enable-shared --without-nss --disable-dict --disable-ftp --disable-imap --disable- ldap --disable-ldaps --disable-pop3 --disable-proxy --disable-rtsp --disable-smtp --disable-telnet --disable-tftp --disable-zlib --without-ca-bundle --without-gnutls --without-libidn --without-librtmp --without-libssh2 --without-nss --without-zlib --with- ssl=/home/yuehy/test/openssl/out
配置不带版本号的库
修改 configure文件
带版本号的库 原始配置
linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
version_type=linux # correct to gnu/linux during the next big refactor
need_lib_prefix=no
need_version=no
library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
soname_spec='$libname$release$shared_ext$major'
finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
不带版本号的库
# This must be glibc/ELF.
linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
version_type=linux # correct to gnu/linux during the next big refactor
need_lib_prefix=no
need_version=no
library_names_spec='$libname$shared_ext'
soname_spec=''
finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=no
libsqlite3.so Android64位库
编译指令
/usr/local/android-ndk-r14b/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-gcc -shared -fPIC -DPIC -I/usr/local/android-ndk-r14b/platforms/android-21/arch-arm64/usr/include -L/usr/local/android-ndk-r14b/platforms/android-21/arch-arm64/usr/lib .libs/sqlite3.o -lz -lm -ldl -g -O2 -Wl,-soname -Wl,libsqlite3.so -o lib/libsqlite3.so
libevent.so Android64位库
编译指令
CPPFLAGS=-I/usr/local/android-ndk-r14b/platforms/android-21/arch-arm64/usr/include LDFLAGS=-L/usr/local/android-ndk-r14b/platforms/android-21/arch-arm64/usr/lib CC=/usr/local/android-ndk-r14b/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-gcc ./configure --prefix=/home/yuehy/test/libevent-2.1.12-stable/out --host=aarch64-linux-gnu --disable-openssl --enable-shared
修改confdefs.h
带版本号的库
# This must be glibc/ELF.
linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
version_type=linux # correct to gnu/linux during the next big refactor
need_lib_prefix=no
need_version=no
library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext'
soname_spec='$libname$release$shared_ext$major'
finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=no
# Some binutils ld are patched to set DT_RUNPATH
if ${lt_cv_shlibpath_overrides_runpath+:} false; then :
$as_echo_n "(cached) " >&6
else
lt_cv_shlibpath_overrides_runpath=no
save_LDFLAGS=$LDFLAGS
save_libdir=$libdir
eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \
LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\""
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
不带版本号的库
# This must be glibc/ELF.
linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
version_type=linux # correct to gnu/linux during the next big refactor
need_lib_prefix=no
need_version=no
library_names_spec='$libname$shared_ext'
soname_spec=''
finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
shlibpath_var=LD_LIBRARY_PATH
shlibpath_overrides_runpath=no
# Some binutils ld are patched to set DT_RUNPATH
if ${lt_cv_shlibpath_overrides_runpath+:} false; then :
$as_echo_n "(cached) " >&6
else
lt_cv_shlibpath_overrides_runpath=no
save_LDFLAGS=$LDFLAGS
save_libdir=$libdir
eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \
LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\""
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
编译libspeex.so Android64位库
编译指令
Android 64
LDFLAGS=I/usr/local/android-ndk-r14b/platforms/android-21/arch-arm64/usr/lib CPPFLAGS=L/usr/local/android-ndk-r14b/platforms/android-21/arch-arm64/usr/include
CC=/usr/local/android-ndk-r14b/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-gcc ./configure --host=aarch64-linux-gnu --target=aarch64-linux-gnu
编译libsrtp.so Android64位库
编译选项
编译指令
linux 64
CC=aarch64-linux-gnu-gcc ./configure --host=arm-linux
android
CPPFLAGS=-I/usr/local/android-ndk-r14b/platforms/android-21/arch-arm64/usr/include LDFLAGS=-L/usr/local/android-ndk-r14b/platforms/android-21/arch-arm64/usr/lib CC=/usr/local/android-ndk-r14b/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-gcc ./configure --host=aarch64-linux-android
生成静态库 make
生成动态库 make libsrtp2.so