How to incorporate existing make file with Android NDK How to incorporate existing make file with Android NDK android android

How to incorporate existing make file with Android NDK


To answer your question, yes Android.mk is the Android build system. Google barely mentions that the "language" of this file is implemented as GNU make macros. The docs want you to describe your project in terms of those macros. They handle all the grungy cross-compilation details. I'm pretty sure Google has taken this approach to improve forward portability of Android.mk files as the development tools evolve.

The upshot is that (and I know you won't want to hear this) the best answer is probably to write a proper NDK Android.mk for your big project from scratch.

This article lays out the same observations I made porting a library of about 800 files and 300k SLOC. Unfortunately I burned almost two weeks reaching the same conclusion: Cross-compilation causes at least some configure scripts to fail (result in erroneous config.h files). I "invented" pretty much the same techniques he's using in the article. But even after I got a clean build, the resulting static library did not work fully. Hours of debugging netted no useful information. [Caveat: I am no kind of config tools expert. A guru probably would have spotted my error. So it goes.] It took me a couple of days to create a clean Android.mk. The resulting library ran all tests first time through. And it has ported cleanly through several revs of development tools.

Unfortunately building a library that uses configure without the auto tools means building your own config.h by hand for the target environment. This might not be as bad as it sounds. IME systems tend to define much more in their configure environments than they actually use. Getting a clear idea of real dependencies may repay the tedious effort during future refactoring.

The summary statement from the article says it all:

Autotool is good only on GNU systems and using it for cross compiling can be really tedious, confusing, error prone or even impossible. The method described here is a hack and should be used at your own risk.

Sorry I don't have a more positive suggestion.


My answer works best in tandem with Gene's answer.

./configure's creation of the config file is based on compiling (and possibly running) small snippets of C code for each test. The success of each test sets a corresponding variable in the config.h.in template to create the config.h. The compile-only tests can be successfully tested in a cross-compile environment. However, the compile and run tests are impossible to run in a cross-compile environment.

Thus, to start the conversion process, you'll need to set the environment variables CPP,CC,LD and other tool aliases to the cross-compiler set of tools (probably the ones from the NDK) and then run ./configure. Once this is done, then you'll need to correct the config.h to match your target environment. This is your most critical and most error prone step.

As for the Android.mk, it follows a format quite close to Makefile.am which can be easily converted into it. You can ignore the Makefile.in and the Makefile, as they are generated from the Makefile.am.

To take an example of file (version 5.11), I ran configure with the following options,

./configure --host arm-toshiba-linux-androideabi --build x86_64-linux-gnu \            --prefix=/data/local/ host_alias=arm-linux-androideabi \           "CFLAGS=--sysroot=~/ndk/platforms/android-8/arch-arm  -Wall -Wextra" \           "CPPFLAGS=--sysroot=~/ndk/platforms/android-8/arch-arm" \            CPP=arm-linux-androideabi-cpp

The next step was to take the src/Makefile.am as below:

MAGIC = $(pkgdatadir)/magiclib_LTLIBRARIES = libmagic.lainclude_HEADERS = magic.hbin_PROGRAMS = fileAM_CPPFLAGS = -DMAGIC='"$(MAGIC)"'AM_CFLAGS = $(CFLAG_VISIBILITY) @WARNINGS@libmagic_la_SOURCES = magic.c apprentice.c softmagic.c ascmagic.c \        encoding.c compress.c is_tar.c readelf.c print.c fsmagic.c \        funcs.c file.h readelf.h tar.h apptype.c \        file_opts.h elfclass.h mygetopt.h cdf.c cdf_time.c readcdf.c cdf.hlibmagic_la_LDFLAGS = -no-undefined -version-info 1:0:0if MINGWMINGWLIBS = -lgnurx -lshlwapielseMINGWLIBS =endiflibmagic_la_LIBADD = $(LTLIBOBJS) $(MINGWLIBS)file_SOURCES = file.cfile_LDADD = libmagic.laCLEANFILES = magic.hEXTRA_DIST = magic.h.inHDR= $(top_srcdir)/src/magic.h.inBUILT_SOURCES = magic.hmagic.h:        ${HDR}        sed -e "s/X.YY/$$(echo @VERSION@ | tr -d .)/" < ${HDR} > $@

And create the Android.mk from this.

The last and most important step was to modify the config.h to accurately reflect the state of the target system. This will be a manual process which I cannot give a workaround for, mainly involving looking into the configure.log, looking into the headers and "invoking" Google. The fruits of this labour are available on XDA.


Here's a solution for doing the things the other way around: buildingboth the external library and the Android package from standard Makefiles.

As a prerequisite, you need to install everything needed to do command lineAndroid development:

  • A standalone toolchain, see the documentation included in the Android NDK;
  • ant.

The structure of the example is: a directory for the external libraryand a directory for the Android sources at the same level with a Makefilein each directory and a top-level, recursive Makefile:

Makefilemylib/    Makefileandroid/    Makefile

The mylib/Makefile builds a static library:

AR=/path/to/standalone/bin/arm-linux-androideabi-arCC=/path/to/standalone/bin/arm-linux-androideabi-gcclibmylib.a: mylib.o    $(AR) rcs libmylib.a mylib.omylib.o: mylib.c    $(CC) -c mylib.c -o mylib.o

The android/Makefile is providing rules to build the Android package:

  • we need a dependency to copy mylib when it's modified;
  • we're using a jni/ndkmake.c file to wrap the calls to mylib and provide android specific stuff;
  • the android package depends on the Java sources and on the shared library.

The Makefile provides two target: release (the default) and debug to build either a release package or a debug one.

NDK_BUILD=/path/to/ndk-buildJAVASRC=src/com/example/ndkmake/NdkMake.javarelease: bin/NdkMake-release-unsigned.apkdebug: bin/NdkMake-debug.apkbin/NdkMake-release-unsigned.apk: libs/armeabi/libndkmake.so $(JAVASRC)ant releasebin/NdkMake-debug.apk: libs/armeabi/libndkmake.so $(JAVASRC)ant debuglibs/armeabi/libndkmake.so: jni/ndkmake.c jni/libmylib.a$(NDK_BUILD)jni/libmylib.a: ../mylib/libmylib.acp ../mylib/libmylib.a jni/libmylib.a

The Android.mk file provides rules to include the static library in the build, as a prebuilt.We're including headers from the mylib library using LOCAL_EXPORT_C_INCLUDES.

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := ndkmakeLOCAL_SRC_FILES := ndkmake.cLOCAL_STATIC_LIBRARIES := mylib-prebuiltinclude $(BUILD_SHARED_LIBRARY)include $(CLEAR_VARS)LOCAL_MODULE := mylib-prebuiltLOCAL_SRC_FILES := libmylib.aLOCAL_EXPORT_C_INCLUDES := ../mylib/include $(PREBUILT_STATIC_LIBRARY)

Now we only need a top-level Makefile to build the two subdirectories:

all: libmylib packagelibmylib:    cd mylib && $(MAKE)package:    cd android && $(MAKE)

Any change to the library, to the jni sources or to the Java sources will trigger a rebuildof the package.