Android.mk (Command Line)

From Crypto++ Wiki
Jump to: navigation, search

Android.mk and Application.mk refer to building the library from the command line using ndk-build and the Android standard build files. Android.mk and Application.mk is a separate project like Autotools and Cmake. The project files are located at GitHub | cryptopp-android.

The Android.mk and Application.mk are based on by Alex Afanasyev's early pull request. The pull request went unmerged because we did not want to add the directory structure to accommodate Android builds.

Since Android.mk and Application.mk are standard Android build files there is not much to using them. Android.mk and Application.mk produce three artifacts. The artifacts are libcryptopp_static.a, libcryptopp_shared.so and cryptest.exe. In practice you will probably only use libcryptopp_static.a.

The Android project files are maintained by the community, and not the library. If you want to use Android build system then download it from GitHub | cryptopp-android. If you have an improvement, then make the change and submit a pull request. It is a separate project to ensure folks don't accidentally use it. (Our unofficial Autotools and CMake projects are separate projects, too).

You should visit C++ Library Support in the Android docs. The Android docs provide a lot of important information that will help you use C++ effectively on Android. For example the docs recommend using ReLinker to relieve you of manually loading libraries in the correct order.

A related page is Android Setup (Command Line), which discusses how to setup an Android build machine. Another is Android (Command Line), which builds the library from the command line using GNUmakefile-cross. A second page of interest is Wrapper DLL, which discusses creating wrapper DLLs and shared objects that garbage collect unused symbols and use small export tables.

NDK Path

ndk-build is part of the Android NDK. The commands shown below were executed with the NDK and SDK on-path. Both ANDROID_NDK_ROOT and ANDROID_SDK_ROOT were set in the environment, and then a new path was exported with export PATH=$PATH:$ANDROID_NDK_ROOT:$ANDROID_SDK_ROOT/tools:$ANDROID_SDK_ROOT/platform-tools. ANDROID_SDK_ROOT is not needed for this wiki page.

Always set ANDROID_NDK_ROOT and ANDROID_SDK_ROOT because the Android tools use them internally. Also see Recommended NDK Directory? on the Android NDK mailing list. Also see Android Setup (Command Line).

Runtime Library

When using Android and C++ you have several C++ runtime libraries to chose from. They include c++_shared (LLVM libc++), gnustl_shared (GNU libstdc++), stlport_shared with static variants of each. The Application.mk uses c++_shared by default because AOSP recommends c++_shared for NDK version 16 and higher.

There are three landmines you have to watch out for. First, you have to be sure GNU's gnustl_shared meets your licensing requirements. Many projects cannot use GPL'd components so be sure gnustl_shared is right for you. Be aware that projects like QT used to build with gnustl_shared so the decision may already be made for you.

Second, all libraries that you link to must use the same runtime library, whether it is c++_shared, gnustl_shared, or stlport_shared. You cannot mix and match runtime libraries, like one library using c++_shared and another library using gnustl_shared. You cannot mix and match shared versus static versions of the same runtime, either. Transgressions will result in hard to diagnose memory problems.

Third, if two or more libraries use a runtime then you must use the shared version of the library. For example, suppose libfoo and libbar both use stlport_static. Because two or more libraries use STLPort stlport_shared must be used. Transgressions will result in hard to diagnose memory problems.

There is a lot more information available for Android and C++. You should visit C++ Library Support in the Android docs for more information.

Application.mk

Application.mk provides the applications settings. You should change the values to suit your taste. The build file is setup to build the library in place. If you drop Android.mk and Application.mk in an Eclipse or Android Studio project then you should delete the lines that set NDK_PROJECT_PATH and APP_BUILD_SCRIPT.

APP_ABI := all
APP_PLATFORM := android-21
APP_STL := c++_shared

CRYPTOPP_ROOT := $(call my-dir)
NDK_PROJECT_PATH := $(CRYPTOPP_ROOT)
APP_BUILD_SCRIPT := $(CRYPTOPP_ROOT)/Android.mk

Android.mk

Android.mk provides the recipes to build the library and test program. Application.mk is setup to build the library in place through the variable CRYPTOPP_PATH. The variable is empty so the concatenation of CRYPTOPP_PATH prepended to a source file like test.cpp results in test.cpp.

LOCAL_PATH := $(call my-dir)

CRYPTOPP_PATH :=
...

If the Crypto++ source files are located one directory up then you would use something like the following. The concatenation of CRYPTOPP_PATH prepended to a source file like test.cpp results in ../cryptopp/test.cpp.

LOCAL_PATH := $(call my-dir)

CRYPTOPP_PATH := ../cryptopp/
...

The rest of the file consists of source files in CRYPTOPP_SRC_FILES in CRYPTOPP_TEST_FILES, and the declarations to build the modules shared object, static library and cryptest.exe program.

ndk-build

ndk-build or Ant can be used to build the library from the command line. The documentation for the build tool is at ndk-build.

If you are building the library in place then your command line will be similar to the following.

cd cryptopp
ndk-build NDK_PROJECT_PATH="$PWD" NDK_APPLICATION_MK="$PWD/Application.mk"

If you are building from Eclipse or Android Studio then drop Application.mk and Android.mk in the jni/ directory and let the IDE build the library for you.

Though Application.mk states APP_ABI := all you can build for a single architecture by overriding APP_ABI like shown below.

cd cryptopp
ndk-build APP_ABI=armeabi-v7a NDK_PROJECT_PATH="$PWD" NDK_APPLICATION_MK="$PWD/Application.mk"

Activity

When you build your Java application or activity you should not link against libcryptopp_shared.so. The shared object includes nearly the entire library and it is large. libcryptopp_shared.so will load slowly because the export table is large and take up a lot of memory.

Instead you should build a wrapper shared object that links against the static archive libcryptopp_static.a. The linker will discard most of the [unused] symbols in the static archive so you will have a smaller and faster shared object that only includes what it needs from the library.

An example of a wrapper shared object is available at Android Activity. Below is a snippet that might be an exported function from your wrapper shared object that exports a "one-shot hash". The full wiki article is available at Wrapper DLL.

#include <sha.h>
#include <stdint.h>

#if __GNUC__ >= 4
  #define DLL_PUBLIC __attribute__ ((visibility ("default")))
  #define DLL_LOCAL  __attribute__ ((visibility ("hidden")))
#else
  #define DLL_PUBLIC
  #define DLL_LOCAL
#endif

extern "C" DLL_PUBLIC
int sha256_hash(uint8_t* digest, size_t dsize,
         const uint8_t* message, size_t msize)
{
    using CryptoPP::Exception;
    using CryptoPP::SHA256;

    try
    {
        SHA256().CalculateTruncatedDigest(digest, dsize, message, msize);
        return 0;  // success
    }
    catch(const Exception&)
    {
        return 1;  // failure
    }
}

Downloads

cryptopp-android - GitHub project with cryptopp-android project files.