1. 程式人生 > 其它 >Android64位庫編譯遇到的問題和處理方法

Android64位庫編譯遇到的問題和處理方法

Android64位庫編譯遇到的問題和處理方法

小舟從此逝,江海度餘生
![小舟從此逝] (https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg3.doubanio.com%2Fview%2Fgroup_topic%2Fl%2Fpublic%2Fp52542311.jpg&refer=http%3A%2F%2Fimg3.doubanio.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1655187062&t=1575d00004032489b529e02bd45b000f

)

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