All Articles

Compile openssl and curl for Android

TL;DR

For anyone that only wants pre-compiled static libraries of openssl and curl, check out this repo and its releases.

Compiling openssl and curl can be a natural request if you are integrating some C libraries into your Android project. Android use four ABIs that are not compatible with modern desktop environments, so we will have to cross-compile those libraries to be able to run them on mobile devices.

Cross Compiler

Cross-compilation is generally easy if we get the right cross-compiler. What cross-compiler do we have for Android? It is included in NDK! Once you have NDK installed, you will find corresponding cross-compilers inside its bundle.

For macOS users, it will be located in $ANDROID_NDK_HOME/toolchains/llvm/prebuilt/$HOST_TAG where $ANDROID_NDK_HOME is the ndk-bundle path and $HOST_TAG is the identifier for your OS. Find your $HOST_TAG in Android NDK docs.

Autotool based build system

We can build some simple C files together with the cross compiler. However, openssl and curl are both complex and large projects using a GNU-autotools-like build system. This means we still need to use their own build system and we need to rightly configure so the final binary is built for Android ABIs.

openssl

curl needs a SSL library so we will build openssl first.

We can find build instructions on its repo. It is pretty in detail. Simply follow the instructions and you shall be able to compile the library.

Here is one of my scripts:

# You need to set `$MIN_SDK_VERSION`, `$ANDROID_NDK_HOME` and `$HOST_TAG` first
export TOOLCHAIN=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/$HOST_TAG
PATH=$TOOLCHAIN/bin:$PATH

./Configure android-arm64 no-shared \
 -D__ANDROID_API__=$MIN_SDK_VERSION \
 --prefix=$PWD/build/arm64-v8a

Just a few caveats:

  1. Using llvm seems better if you are compiling on macOS, so put $ANDROID_NDK_HOME/toolchains/llvm/prebuilt/$HOST_TAG/bin into PATH. Then autotools can use the right compiler for the job.
  2. The corresponding arguments for four ABIs are android-arm64, android-arm, android-x86 and android-x86_64.
  3. You can add no-shared to Configure if a static library is wanted.
  4. Pay attention how ./Configure is called — there is no dash or option name.
  5. Add --prefix because we do not want the library to be installed on the system which is default.

After calling Configure, autotools will generate correct Makefiles for the ABI.

Then run:

make
make install

You will see all include, lib and bin in prefix directory.

For a full script, see build-openssl.sh

curl

curl does not use Configure for Makefile generations but a similar one named configure.

Before all, we first need to generate a special header file to proceed with the building.

Run ./buildconf in curl directory, or you will get a not found error for curl_config.h because it is generated by buildconf. Just run it for a relatively short time and kill the process, curl_config.h will be available.

Building curl is a little trickier than with openssl. We need to declare all cross-compiling tools first to make it work.

For example, to compile against arm64 ABI, we need to first export the following environment variables:

# arm64
export TARGET_HOST=aarch64-linux-android
export TOOLCHAIN=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/$HOST_TAG
PATH=$TOOLCHAIN/bin:$PATH
export AR=$TOOLCHAIN/bin/$TARGET_HOST-ar
export AS=$TOOLCHAIN/bin/$TARGET_HOST-as
export CC=$TOOLCHAIN/bin/$TARGET_HOST$MIN_SDK_VERSION-clang
export CXX=$TOOLCHAIN/bin/$TARGET_HOST$MIN_SDK_VERSION-clang++
export LD=$TOOLCHAIN/bin/$TARGET_HOST-ld
export RANLIB=$TOOLCHAIN/bin/$TARGET_HOST-ranlib
export STRIP=$TOOLCHAIN/bin/$TARGET_HOST-strip
export SSL_DIR=$PWD/../openssl/build/arm64-v8a

SSL_DIR is for locating openssl if we want to use SSL with curl later.

Then we have the standard autotools’ way:

./configure --host=$TARGET_HOST \
            --target=$TARGET_HOST \
            --prefix=$PWD/build/arm64-v8a \
            --with-ssl=$SSL_DIR \
            --disable-shared

Here we only compiled static ones. Building shared libraries with some ARM ABI may cause problems. It may be a bug with NDK toolchains so I recommend sticking to static ones.

You can continue adding more options to disable functions, reducing the library size.

Then run:

make
make install

Find all stuff in prefix directory.

For a full script, see build-curl.sh

Summary

You can also combine all the environment variable setup in shell scripts. See my-build.sh for example.

Checkout this repo and also this post to see how to integrate compiled static libraries into an existing Android project, including Android.mk setup and JNI configurations.