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

posted @ 2022-05-15 14:27  balder_m  阅读(1181)  评论(0编辑  收藏  举报