NDK libcurl编译和兼容性问题解决

在android开发过程中,无论是java层或者native层,我们经常会写一些关键日志信息到文件中,方便定位问题,可能存在将日志文件进行上传到服务器上,或者需要从服务器上下载一些配置信息文件,当然我们可以通过java层的http请求进行上传或者下载操作,但是其实为了更好的跨平台特性,我们可以使用libcurl来实现。

简介

libcurl为一个免费开源的,客户端url传输库,支持DICT, FILE, FTP, FTPS, Gopher, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, POP3, POP3S, RTMP, RTSP, SCP, SFTP, SMTP, SMTPS, Telnet and TFTP等协议。
libcurl也支持SSL证书,HTTP POST, HTTP PUT,FTP上传,基于表单的HTTP上传,代理(proxies)、cookies、用户名/密码认证(Basic, Digest, NTLM等)、下载文件断点续传,上载文件断点续传(file transfer resume),http代理服务器管道(proxy tunneling)等。这通常我们需要与openssl库共同配合来完成加密请求。
libcurl是高度可移植的,可以工作在不同的平台上,支持Windows,Unix,Linux等。
libcurl是免费的,线程安全的,IPV6兼容的,同时它还有很多其他非常丰富的特性。libcurl已经被很多知名的大企业以及应用程序所采用。
总结起来:curl的特性就是开源、支持协议多、支持ssl、支持跨平台、支持ipv6等等诸多特性。

在Android平台的编译

环境准备

  1. ndk环境,ndk环境请自行下载
  2. curl源码(7.64.1),下载地址
  3. 交叉编译工具链,请参考自定义NDK交叉编译工具类

编译

定义环境变量

export TOOLCHAIN=$ANDROID_HOME/toolchain  // toolchain路径,自行修改
export PKG_CONFIG_LIBDIR=$TOOLCHAIN/lib/pkgconfig
export CROSS_SYSROOT=$TOOLCHAIN/sysroot
export PATH=$TOOLCHAIN/bin:$PATH
export TOOL=arm-linux-androideabi
export CC=$TOOLCHAIN/bin/${TOOL}-gcc
export CXX=$TOOLCHAIN/bin/${TOOL}-g++
export LINK=${CXX}
export LD=$TOOLCHAIN/bin/${TOOL}-ld
export AR=$TOOLCHAIN/bin/${TOOL}-ar
export RANLIB=$TOOLCHAIN/bin/${TOOL}-ranlib
export STRIP=$TOOLCHAIN/bin/${TOOL}-strip
export ARCH_FLAGS="-mthumb"
export ARCH_LINK=
export CFLAGS="${ARCH_FLAGS} -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -finline-limit=64"
export CXXFLAGS="${CFLAGS} -frtti -fexceptions"
export LDFLAGS="${ARCH_LINK}"

编译并安装

cd curl-7.64.1
autoreconf -i
./configure --prefix=$TOOLCHAIN/sysroot/usr/local \
       --with-sysroot=$TOOLCHAIN/sysroot \
       --host=arm-linux-androideabi \
       --with-ssl=$TOOLCHAIN/sysroot/usr/local \
       --with-nghttp2=$TOOLCHAIN/sysroot/usr/local \
       --enable-ipv6 \
       --enable-static \
       --enable-threaded-resolver \
       --disable-dict \
       --disable-gopher \
       --disable-ldap --disable-ldaps \
       --disable-manual \
       --disable-pop3 --disable-smtp --disable-imap \
       --disable-rtsp \
       --disable-shared \
       --disable-smb \
       --disable-telnet \
       --disable-verbose

make -j4
make install

./configure ...过程自己根据当前项目的需求,disable不相关的配置,减少库体积。

生成库

编译完库,生成在./configure时指定的prefix路径下


2708495-0fc97532a0c8c4ff.png
生成目录

将include和lib中的静态库引用到android工程中进行使用。

遇到问题

生成的库放在ndk中使用时,我们ndk如果APP_PLATFORM目标小于android-21,也就是LOLLIPOP版本以下时,编译会报错:undefined reference to 'getpwuid_r',链接不到getpwuid_r方法,其实是在android-21以下的编译环境中,没有该方法,如果要使用,必须将APP_PLATFORM提升到android-21,对应的,我们的app minSdkVersion也必须要升到21。升级支持最低系统版本号这种做法,其实不是我们想要的。
没办法,只能去看curl源码,发现我们在使用到该方法的地方,都有用宏HAVE_GETPWUID_R控制

#if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID)
    if((!username || !username[0]) &&
       !getpwuid_r(geteuid(), &pw, pwbuf, sizeof(pwbuf), &pw_res) &&
       pw_res) {
      username = pw.pw_name;
    }
#endif

那么只要在编译的时候,将该宏undefine,在编译和运行时就能跳过该方法,具体做法如下:

export CFLAGS="${ARCH_FLAGS} -fpic -ffunction-sections -funwind-tables -fstack-protector -fno-strict-aliasing -finline-limit=64 -DHAVE_GETPWUID_R=0"

或者在使用到该宏的源码处,取消宏定义

#undef HAVE_GETPWUID_R

这样curl重新编译,就能够在android-21以下的系统版本中使用啦...

猜你喜欢

转载自blog.csdn.net/weixin_34200628/article/details/90879221
今日推荐