Compile libcurl 7.37.0 with Android 4.4 or other versions

Recently I need compile libcurl for different platforms, since cocos-2dx 3.0 ships with libcurl 7.26.0 and there are several fixes in newer versions according to changelog. There are several blogs describing how to build libcurl with android source, such as porting-of-libcurl-to-android-os-using, How_to_compile_libcurl and Android ndk下编译libcurl. However, they are all out dated, especially android source has changed a lot!

After struggling a whole weekend, I finally compiled libcurl 7.37.0 with android 4.4 source. The steps described in packages/Android/Android.mk skip many details. I’ll explain every steps and hope you can make it. If you use the similar version, you could just copy & paste mine.

Build Environment (Android 4.4)

Follow instructions in Download and Building and build android first. If you encounter connecting problems in China, you may refer to 如何在国内下载android源代码. My android source folder is put at /home/anthony/android.

Generate LIBS

In order to determine which libs are needed, we first make an execuable library to see arguments passed in. Run make dhcpcd showcommands at /home/anthony/android, and we will get this in terminal output:

prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8/bin/arm-linux-androideabi-g++ -nostdlib -Bdynamic -pie -Wl,-dynamic-linker,/system/bin/linker -Wl,--gc-sections -Wl,-z,nocopyreloc  -Lout/target/product/generic/obj/lib -Wl,-rpath-link=out/target/product/generic/obj/lib out/target/product/generic/obj/lib/crtbegin_dynamic.o         out/target/product/generic/obj/EXECUTABLES/dhcpcd_intermediates/arp.o out/target/product/generic/obj/EXECUTABLES/dhcpcd_intermediates/bind.o out/target/product/generic/obj/EXECUTABLES/dhcpcd_intermediates/common.o out/target/product/generic/obj/EXECUTABLES/dhcpcd_intermediates/control.o out/target/product/generic/obj/EXECUTABLES/dhcpcd_intermediates/dhcp.o out/target/product/generic/obj/EXECUTABLES/dhcpcd_intermediates/dhcpcd.o out/target/product/generic/obj/EXECUTABLES/dhcpcd_intermediates/duid.o out/target/product/generic/obj/EXECUTABLES/dhcpcd_intermediates/eloop.o out/target/product/generic/obj/EXECUTABLES/dhcpcd_intermediates/if-options.o out/target/product/generic/obj/EXECUTABLES/dhcpcd_intermediates/if-pref.o out/target/product/generic/obj/EXECUTABLES/dhcpcd_intermediates/ipv4ll.o out/target/product/generic/obj/EXECUTABLES/dhcpcd_intermediates/net.o out/target/product/generic/obj/EXECUTABLES/dhcpcd_intermediates/signals.o out/target/product/generic/obj/EXECUTABLES/dhcpcd_intermediates/configure.o out/target/product/generic/obj/EXECUTABLES/dhcpcd_intermediates/if-linux.o out/target/product/generic/obj/EXECUTABLES/dhcpcd_intermediates/if-linux-wireless.o out/target/product/generic/obj/EXECUTABLES/dhcpcd_intermediates/lpf.o out/target/product/generic/obj/EXECUTABLES/dhcpcd_intermediates/platform-linux.o out/target/product/generic/obj/EXECUTABLES/dhcpcd_intermediates/compat/closefrom.o out/target/product/generic/obj/EXECUTABLES/dhcpcd_intermediates/ifaddrs.o out/target/product/generic/obj/EXECUTABLES/dhcpcd_intermediates/ipv6rs.o        -Wl,--whole-archive   -Wl,--no-whole-archive   out/target/product/generic/obj/STATIC_LIBRARIES/libcompiler_rt-extras_intermediates/libcompiler_rt-extras.a    -lc -lcutils -lm -lnetutils -lstdc++  -o out/target/product/generic/obj/EXECUTABLES/dhcpcd_intermediates/LINKED/dhcpcd  -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--warn-shared-textrel -Wl,--fatal-warnings -Wl,--icf=safe -Wl,--fix-cortex-a8    -Wl,--no-undefined prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8/bin/../lib/gcc/arm-linux-androideabi/4.8/../../../../arm-linux-androideabi/lib/armv7-a/libatomic.a prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8/bin/../lib/gcc/arm-linux-androideabi/4.8/armv7-a/libgcc.a out/target/product/generic/obj/lib/crtend_android.o 

This indicates the link step and we can find libraries like -lc -lcutils -lm -lnetutils -lstdc++ and libatomic.a libgcc.a crtbegin_dynamic.o crtend_android.o.

Put libcurl into android source

Extract libcurl into android/external and rename it from curl-7.37.0 to curl. Now we need to fix two places in packages/Android/Android.mk:

  • Add in line 73: LOCAL_C_INCLUDES += $(LOCAL_PATH)/include/ $(LOCAL_PATH)/lib/
  • Comment line 86: #ALL_PREBUILT += $(LOCAL_PATH)/NOTICE

Generate CPPFLAGS and CFLAGS

Similar to the previous step, run make libcurl showcommands at /home/anthony/android and we will fail with the following output (Remember we haven’t ./configure yet):

prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8/bin/arm-linux-androideabi-gcc 
-I external/curl/packages/Android/../../include/ -I external/curl/packages/Android/../.. -I out/target/product/generic/obj/STATIC_LIBRARIES/libcurl_intermediates -I out/target/product/generic/gen/STATIC_LIBRARIES/libcurl_intermediates -I libnativehelper/include/nativehelper -isystem system/core/include -isystem hardware/libhardware/include -isystem hardware/libhardware_legacy/include -isystem hardware/ril/include -isystem libnativehelper/include -isystem frameworks/native/include -isystem frameworks/native/opengl/include -isystem frameworks/av/include -isystem frameworks/base/include -isystem external/skia/include -isystem out/target/product/generic/obj/include -isystem bionic/libc/arch-arm/include -isystem bionic/libc/include -isystem bionic/libstdc++/include -isystem bionic/libc/kernel/uapi -isystem bionic/libc/kernel/uapi/asm-arm -isystem bionic/libm/include -isystem bionic/libm/include/arm -c -fno-exceptions -Wno-multichar -msoft-float -ffunction-sections -fdata-sections -funwind-tables -fstack-protector -Wa,--noexecstack -Werror=format-security -D_FORTIFY_SOURCE=2 -fno-short-enums -no-canonical-prefixes -fno-canonical-system-headers -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -include build/core/combo/include/arch/linux-arm/AndroidConfig.h -I build/core/combo/include/arch/linux-arm/ -Wno-unused-but-set-variable -fno-builtin-sin -fno-strict-volatile-bitfields -Wno-psabi -mthumb-interwork -DANDROID -fmessage-length=0 -W -Wall -Wno-unused -Winit-self -Wpointer-arith -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -DNDEBUG -g -Wstrict-aliasing=2 -fgcse-after-reload -frerun-cse-after-loop -frename-registers -DNDEBUG -UDEBUG -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -Wpointer-arith -Wwrite-strings -Wunused -Winline -Wnested-externs -Wmissing-declarations -Wmissing-prototypes -Wno-long-long -Wfloat-equal -Wno-multichar -Wsign-compare -Wno-format-nonliteral -Wendif-labels -Wstrict-prototypes -Wdeclaration-after-statement -Wno-system-headers -DHAVE_CONFIG_H -fPIC -MD -MF out/target/product/generic/obj/STATIC_LIBRARIES/libcurl_intermediates/lib/file.d -o out/target/product/generic/obj/STATIC_LIBRARIES/libcurl_intermediates/lib/file.o external/curl/packages/Android/../../lib/file.c

We should copy -I -isystem and flags like -W -D -M into the following step.

Build.sh

Now we have enough parameters needed to pass in, so we can write a script called build.sh. Follow Dan Fandrich’s instructions: putting the -I, -isystem and -D options into CPPFLAGS, putting the -W, -m, -f, -O and -nostdlib options into CFLAGS, and putting the -Wl, -L and -l options into LIBS, along with the path to the files libgcc.a, crtbegin_dynamic.o, and ccrtend_android.o. Remember that the paths must be absolute since you will not be running configure from the same directory as the Android make. The normal cross-compiler options must also be set. Note that the -c, -o, -MD and similar flags must not be set.

Here is my script, with parameters from the above steps.

#!/bin/sh

ANDROID_ROOT="$HOME/android" && \
PATH=$ANDROID_ROOT/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8/bin:$PATH \
CPPFLAGS="-I $ANDROID_ROOT/external/curl/packages/Android/../../include/ -I $ANDROID_ROOT/external/curl/packages/Android/../.. -I $ANDROID_ROOT/out/target/product/generic/obj/STATIC_LIBRARIES/libcurl_intermediates -I $ANDROID_ROOT/out/target/product/generic/gen/STATIC_LIBRARIES/libcurl_intermediates -I $ANDROID_ROOT/libnativehelper/include/nativehelper -isystem $ANDROID_ROOT/system/core/include -isystem $ANDROID_ROOT/hardware/libhardware/include -isystem $ANDROID_ROOT/hardware/libhardware_legacy/include -isystem $ANDROID_ROOT/hardware/ril/include -isystem $ANDROID_ROOT/libnativehelper/include -isystem $ANDROID_ROOT/frameworks/native/include -isystem $ANDROID_ROOT/frameworks/native/opengl/include -isystem $ANDROID_ROOT/frameworks/av/include -isystem $ANDROID_ROOT/frameworks/base/include -isystem $ANDROID_ROOT/external/skia/include -isystem $ANDROID_ROOT/out/target/product/generic/obj/include -isystem $ANDROID_ROOT/bionic/libc/arch-arm/include -isystem $ANDROID_ROOT/bionic/libc/include -isystem $ANDROID_ROOT/bionic/libstdc++/include -isystem $ANDROID_ROOT/bionic/libc/kernel/uapi -isystem $ANDROID_ROOT/bionic/libc/kernel/uapi/asm-arm -isystem $ANDROID_ROOT/bionic/libm/include -isystem $ANDROID_ROOT/bionic/libm/include/arm -include $ANDROID_ROOT/build/core/combo/include/arch/linux-arm/AndroidConfig.h -I $ANDROID_ROOT/build/core/combo/include/arch/linux-arm/ -D_FORTIFY_SOURCE=0 -DANDROID -DNDEBUG -DNDEBUG -UDEBUG -DHAVE_CONFIG_H " \
CFLAGS="-nostdlib -fno-exceptions -Wno-multichar -msoft-float -ffunction-sections -fdata-sections -funwind-tables -fstack-protector -Wa,--noexecstack -Werror=format-security -fno-short-enums -no-canonical-prefixes -fno-canonical-system-headers -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -Wno-unused-but-set-variable -fno-builtin-sin -fno-strict-volatile-bitfields -Wno-psabi -mthumb-interwork -fmessage-length=0 -W -Wall -Wno-unused -Winit-self -Wpointer-arith -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -g -Wstrict-aliasing=2 -fgcse-after-reload -frerun-cse-after-loop -frename-registers -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -Wpointer-arith -Wwrite-strings -Wunused -Winline -Wnested-externs -Wmissing-declarations -Wmissing-prototypes -Wno-long-long -Wfloat-equal -Wno-multichar -Wsign-compare -Wno-format-nonliteral -Wendif-labels -Wstrict-prototypes -Wdeclaration-after-statement -Wno-system-headers -fPIC " \
LDFLAGS="-L$ANDROID_ROOT/out/target/product/generic/obj/lib " \
LIBS="$ANDROID_ROOT/out/target/product/generic/obj/lib/crtbegin_dynamic.o $ANDROID_ROOT/out/target/product/generic/obj/lib/crtend_android.o $ANDROID_ROOT/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8/lib/gcc/arm-linux-androideabi/4.8/armv7-a/libgcc.a -lc -lcutils -lm -lnetutils -lstdc++ " \
./configure CC=arm-linux-androideabi-gcc --host=arm-linux-androideabi --host=arm-eabi --disable-shared --disable-tftp --disable-sspi --disable-ipv6 --disable-ldaps --disable-ldap --disable-telnet --disable-pop3 --disable-ftp --without-ssl --disable-imap --disable-smtp --disable-pop3 --disable-rtsp --disable-ares --without-ca-bundle --disable-warnings --disable-manual --without-nss --enable-shared --without-zlib --without-random

Configure and Make

Run the script to configure by ./build.sh and make libcurl from android source root. You will find what you want in out/target/product/generic/obj:

Downgrade to lower Android version

If you wish to compile with lower version, the first thing you need is repo init -b xxx and repo sync to get a different android source.

Attention: you should use the corresponding APP_PLATFORM in NDK when building apps, and don’t forget android:minSdkVersion!

Android 4.3

#!/bin/sh

ANDROID_ROOT="$HOME/android" && \
PATH=$ANDROID_ROOT/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7/bin:$PATH \
CPPFLAGS="-I $ANDROID_ROOT/external/curl-7.37.0/packages/Android/../../include/ -I $ANDROID_ROOT/external/curl-7.37.0/packages/Android/../../lib/ -I $ANDROID_ROOT/external/curl-7.37.0/packages/Android/../.. -I $ANDROID_ROOT/out/target/product/generic/obj/STATIC_LIBRARIES/libcurl_intermediates -I $ANDROID_ROOT/libnativehelper/include/nativehelper -isystem $ANDROID_ROOT/system/core/include -isystem $ANDROID_ROOT/hardware/libhardware/include -isystem $ANDROID_ROOT/hardware/libhardware_legacy/include -isystem $ANDROID_ROOT/hardware/ril/include -isystem $ANDROID_ROOT/libnativehelper/include -isystem $ANDROID_ROOT/frameworks/native/include -isystem $ANDROID_ROOT/frameworks/native/opengl/include -isystem $ANDROID_ROOT/frameworks/av/include -isystem $ANDROID_ROOT/frameworks/base/include -isystem $ANDROID_ROOT/external/skia/include -isystem $ANDROID_ROOT/out/target/product/generic/obj/include -isystem $ANDROID_ROOT/bionic/libc/arch-arm/include -isystem $ANDROID_ROOT/bionic/libc/include -isystem $ANDROID_ROOT/bionic/libstdc++/include -isystem $ANDROID_ROOT/bionic/libc/kernel/common -isystem $ANDROID_ROOT/bionic/libc/kernel/arch-arm -isystem $ANDROID_ROOT/bionic/libm/include -isystem $ANDROID_ROOT/bionic/libm/include/arm -isystem $ANDROID_ROOT/bionic/libthread_db/include -I $ANDROID_ROOT/build/core/combo/include/arch/linux-arm/ -include $ANDROID_ROOT/build/core/combo/include/arch/linux-arm/AndroidConfig.h -D_FORTIFY_SOURCE=0 -DANDROID -DNDEBUG -DNDEBUG -UDEBUG -DHAVE_CONFIG_H" \
CFLAGS="-nostdlib -fno-exceptions -Wno-multichar -msoft-float -fpic -fPIE -ffunction-sections -fdata-sections -funwind-tables -fstack-protector -Wa,--noexecstack -Werror=format-security -fno-short-enums -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -Wno-unused-but-set-variable -fno-builtin-sin -fno-strict-volatile-bitfields -Wno-psabi -mthumb-interwork -fmessage-length=0 -W -Wall -Wno-unused -Winit-self -Wpointer-arith -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -g -Wstrict-aliasing=2 -fgcse-after-reload -frerun-cse-after-loop -frename-registers -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -Wpointer-arith -Wwrite-strings -Wunused -Winline -Wnested-externs -Wmissing-declarations -Wmissing-prototypes -Wno-long-long -Wfloat-equal -Wno-multichar -Wsign-compare -Wno-format-nonliteral -Wendif-labels -Wstrict-prototypes -Wdeclaration-after-statement -Wno-system-headers -MD -MF" \
LDFLAGS="-L$ANDROID_ROOT/out/target/product/generic/obj/lib " \
LIBS="$ANDROID_ROOT/out/target/product/generic/obj/lib/crtbegin_dynamic.o $ANDROID_ROOT/out/target/product/generic/obj/lib/crtend_android.o $ANDROID_ROOT/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7/lib/gcc/arm-linux-androideabi/4.7/armv7-a/libgcc.a -lc -lcutils -lnetutils -lc -lstdc++ -lm " \
./configure CC=arm-linux-androideabi-gcc --host=arm-linux-androideabi --host=arm-eabi --disable-shared --disable-tftp --disable-sspi --disable-ipv6 --disable-ldaps --disable-ldap --disable-telnet --disable-pop3 --disable-ftp --without-ssl --disable-imap --disable-smtp --disable-pop3 --disable-rtsp --disable-ares --without-ca-bundle --disable-warnings --disable-manual --without-nss --enable-shared --without-zlib --without-random

Android 2.3.3

You may need downgrade your gcc and do as the above.

#!/bin/sh

ANDROID_ROOT="$HOME/android" && \
PATH=$ANDROID_ROOT/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin:$PATH \
CPPFLAGS="-I $ANDROID_ROOT/external/curl/packages/Android/../../include -I $ANDROID_ROOT/external/curl/packages/Android/../../lib -I $ANDROID_ROOT/external/curl/packages/Android/../.. -I $ANDROID_ROOT/out/target/product/generic/obj/EXECUTABLES/curl_intermediates -I $ANDROID_ROOT/out/target/product/generic/obj/STATIC_LIBRARIES/libwebcore_intermediates -I $ANDROID_ROOT/dalvik/libnativehelper/include/nativehelper -I $ANDROID_ROOT/system/core/include -I $ANDROID_ROOT/hardware/libhardware/include -I $ANDROID_ROOT/hardware/libhardware_legacy/include -I $ANDROID_ROOT/hardware/ril/include -I $ANDROID_ROOT/dalvik/libnativehelper/include -I $ANDROID_ROOT/frameworks/base/include -I $ANDROID_ROOT/frameworks/base/opengl/include -I $ANDROID_ROOT/frameworks/base/native/include -I $ANDROID_ROOT/external/skia/include -I $ANDROID_ROOT/out/target/product/generic/obj/include -I $ANDROID_ROOT/bionic/libc/arch-arm/include -I $ANDROID_ROOT/bionic/libc/include -I $ANDROID_ROOT/bionic/libstdc++/include -I $ANDROID_ROOT/bionic/libc/kernel/common -I $ANDROID_ROOT/bionic/libc/kernel/arch-arm -I $ANDROID_ROOT/bionic/libm/include -I $ANDROID_ROOT/bionic/libm/include/arch/arm -I $ANDROID_ROOT/bionic/libthread_db/include -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -include $ANDROID_ROOT/system/core/include/arch/linux-arm/AndroidConfig.h -I $ANDROID_ROOT/system/core/include/arch/linux-arm/ -DANDROID -DNDEBUG -UDEBUG -DHAVE_CONFIG_H " \
CFLAGS="-nostdlib -fno-exceptions -Wno-multichar -msoft-float -fpic -ffunction-sections -funwind-tables -fstack-protector -Wa,--noexecstack -Werror=format-security -fno-short-enums -march=armv5te -mtune=xscale -Wno-psabi -mthumb-interwork -fmessage-length=0 -W -Wall -Wno-unused -Winit-self -Wpointer-arith -Werror=return-type -Werror=non-virtual-dtor -Werror=address -Werror=sequence-point -g -Wstrict-aliasing=2 -finline-functions -fno-inline-functions-called-once -fgcse-after-reload -frerun-cse-after-loop -frename-registers -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -Wpointer-arith -Wwrite-strings -Wunused -Winline -Wnested-externs -Wmissing-declarations -Wmissing-prototypes -Wno-long-long -Wfloat-equal -Wno-multichar -Wsign-compare -Wno-format-nonliteral -Wendif-labels -Wstrict-prototypes -Wdeclaration-after-statement -Wno-system-headers -MD" \
LDFLAGS="-L$ANDROID_ROOT/out/target/product/generic/obj/lib " \
LIBS="$ANDROID_ROOT/out/target/product/generic/obj/lib/crtbegin_dynamic.o $ANDROID_ROOT/out/target/product/generic/obj/lib/crtend_android.o $ANDROID_ROOT/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/lib/gcc/arm-eabi/4.4.3/libgcc.a -lc -llog -lcutils -lstdc++ -lm" \
./configure CC=arm-eabi-g++ --host=arm-eabi --disable-shared --disable-tftp --disable-sspi --disable-ipv6 --disable-ldaps --disable-ldap --disable-telnet --disable-pop3 --disable-ftp --without-ssl --disable-imap --disable-smtp --disable-pop3 --disable-rtsp --disable-ares --without-ca-bundle --disable-warnings --disable-manual --without-nss --enable-shared --without-zlib --without-random

bionic ERROR

This is not specified to libcurl itself. This happens for builds with higher version Android like the following errors:

bionic/libc/include/string.h:109: error: undefined reference to '__memcpy_chk'
bionic/libc/include/stdio.h:496: error: undefined reference to '__sprintf_chk'
bionic/libc/include/string.h:109: error: undefined reference to '__memcpy_chk'

You should disable _FORTIFY_SOURCE in the build.sh! These checks are implemented in Android source rather than NDK so you will get these errors.

Solution First of all, check your build.sh(or other scrips) and ensure D_FORTIFY_SOURCE=0. Second, add -D_FORTIFY_SOURCE=0 into LOCAL_CFLAGS in Android.mk.

You could check your libraries with nm:

anthony@anthony-VirtualBox:~$ nm Downloads/libcurl_4.3.a |grep __memcpy_chk
U __memcpy_chk
U __memcpy_chk
anthony@anthony-VirtualBox:~$ nm android/out/target/product/generic/obj/STATIC_LIBRARIES/libcurl_intermediates/libcurl.a |grep __memcpy_chk
anthony@anthony-VirtualBox:~$

The new library with the macro does not have these chk any more!