Android Build cookbook| Build Apps or Libraries with Make file
Android provides different build systems to compile, deploy and convert your source code into object code. The one which is used in Android Studio is Gradle build system and another one which is used in AOSP to describe the source and libraries is Make file(Android.mk).
The Android.mk file is written to describe your sources and shared libraries to the build system. You can define several modules in a single Android.mk or you can write several Android.mk files, each defining single module.
A module can be one of the following types:
- An android program that is compiled and packaged to generate an APK file.
- A JAVA library program, compiled and packaged to generate a JAR file.
- C/C++ program, compiled to generate an executable C/C++ application.
- C/C++ static library, compile and generate C/C++ static library, and package it into .a file
- C/C++ shared library, compile and generate C/C++ shared library and packaged it into .so file.
All Android.mk files are parsed by the build system before any build occurs. These files are tiny GNU make file fragments that will be parsed more than once by the build system.
Let’s see the code snippet, that will help you quickly build the common tasks like building an APK, building a static or shared library or signing the APK with platform key.
Building a simple APK using Android make file (Android.mk)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# Build all java files in the java subdirectory
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res \
# Name of the APK to build
LOCAL_PACKAGE_NAME := LocalPackage
# Tell it to build an APK
include $(BUILD_PACKAGE)
Now, let’s explain these lines:
LOCAL_PATH := $(call my-dir)
An Android.mk must begin with the definition of the LOCAL_PATH variable. It is used to locate source files in the development tree. In this example, the macro function ‘my-dir‘, provided by the build system, is used to return the path of the current directory (i.e. the directory containing the Android.mk file itself).
include $(CLEAR_VARS)
The CLEAR_VARS variable is a script and points to a special GNU Makefile that will clear all LOCAL_XXX variables for you such as LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES, etc… It does not clear LOCAL_PATH. This is because all build control files are parsed in a single GNU make execution context where all variables are global.
LOCAL_SRC_FILES := $(call all-subdir-java-files)
This is to include all the java source files present in the subdirectories that the build system uses to generate the module.
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res \
This is to include the resource files associated with the application
LOCAL_PACKAGE_NAME := LocalPackage
This variable will tell the build system, what would be the name of the module you are building.
include $(BUILD_PACKAGE)
Just like CLEAR_VAR, BUILD_PACKAGE will also points to a script that will collect all the information you have provided in the LOCAL_XXX and tell the build system to build and APK out of it.
Building an APK that depends on static JAR using Android make file (Android.mk)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# List of static libraries to include in the package
LOCAL_STATIC_JAVA_LIBRARIES := static-library
# Build all java files in the java subdirectory
LOCAL_SRC_FILES := $(call all-subdir-java-files)
# Name of the APK to build
LOCAL_PACKAGE_NAME := LocalPackage
# Tell it to build an APK
include $(BUILD_PACKAGE)
LOCAL_STATIC_JAVA_LIBRARIES := static-library
This variable is to include any static JAVA libraries in your module. For example, Suppose you want to use support-v7- appcompact library, then use it like this:
LOCAL_STATIC_JAVA_LIBRARIES += android-support-v7-appcompat
Or, if you want to use any local library that you have built, then use it like this:
LOCAL_STATIC_JAVA_LIBRARIES += myLib
Building an APK signed with platform keys
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# Build all java files in the java subdirectory
LOCAL_SRC_FILES := $(call all-subdir-java-files)
# Name of the APK to build
LOCAL_PACKAGE_NAME := LocalPackage
LOCAL_CERTIFICATE := platform
# Tell it to build an APK
include $(BUILD_PACKAGE)
LOCAL_CERTIFICATE := platform
This variable will tell the build system, sign the module or APK with platform keys.
Building apk Signed with vendor specific key
LOCAL_CERTIFICATE := vendor/example/certs/app
Here everything will be same as above, only the LOCAL_CERTIFICATE will point to the location where certificates are present.
Now, you have a prebuilt APK and want to include it in the build tree. Let’s see how to do it.
Including a prebuilt apk in build tree using Android.mk file
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# Module name should match apk name to be installed.
LOCAL_MODULE := LocalModuleName
LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
include $(BUILD_PREBUILT)
Here the LOCAL_SRC_FILE will now point to your APK. The LOCAL_MODULE_CLASS will help the system to determine the intermediate file storage location such as the final compiled output, for APPS, the intermediate location will be obj/APPS. We have to specify the file type such as APPS for apk files, SHARED_LIBRARIES for dynamic libraries, EXECUTABLES for bin files, ETC for other files.
The LOCAL_MODULE_CLASS options are:
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_CLASS := STATIC_LIBRARIES
LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_MODULE_CLASS := FAKE
LOCAL_MODULE_CLASS := JAVA_LIBRARIES
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
This variable indicates the suffix of the target package after compiling the link. For .so files it will be .so and for APK it will be COMMON_ANDROID_PACKAGE_SUFFIX
Include $(BUILD_PREBUILT)
It is a script which tells the build system, that module is pre-compiled and pre processing.
Building static JAVA libraries using Android.mk file
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# Build all java files in the java subdirectory
LOCAL_SRC_FILES := $(call all-subdir-java-files)
# Any libraries that this library depends on
LOCAL_JAVA_LIBRARIES := android.test.runner
# The name of the jar file to create
LOCAL_MODULE := sample
# Build a static jar file.
include $(BUILD_STATIC_JAVA_LIBRARY)
LOCAL_JAVA_LIBRARIES := android.test.runner
This variable will define any library, that the current building library is dependent on. In this example, our Sample library is depending on android.test.runner JAVA library.
include $(BUILD_STATIC_JAVA_LIBRARY)
This is the script which will build the static JAVA library.
Building C/C++ Executable file
LOCAL_PATH:= $(call my-dir)include $(CLEAR_VARS)
LOCAL_MODULE := SampleModule
LOCAL_SRC_FILES := helloworld.cpp CalculateVolume.cpp
LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_LIBRARIES := libutils libcutils liblog libcinclude $(BUILD_EXECUTABLE)
LOCAL_STATIC_LIBRARIES := libutils libcutils liblog libc
This variable contains the list of static libraries, required by the module in order to compile.
include $(BUILD_EXECUTABLE)
This will tell the build system to build an executable object.
Let see Android.mk variables
First see the System variables
include $(CLEAR_VARS)
Points to a build script, clear all LOCAL_XXX variables except LOCAL_PATH
BUILD_SHARED_LIBRARY
Points to the build script to compile listed source into shared library based on the LOCAL_XXX variables described in the make file.
BUILD_STATIC_LIBRARY
Points to the build script to compile listed source into static library based on the LOCAL_XXX variables described in the make file. include $(BUILD_STATIC_LIBRARY) will generate a file called lib$(LOCAL_MODULE).a
BUILD_PREBUILT
Points to the build script to include pre-compiled and pre processed modules in the build system
Now, let’s see the Local variables
LOCAL_CPP_EXTENSION
Optional variable, that points to C++ code file. The default is .cpp but it can be changed, for e.g:
LOCAL_CPP_EXTENSION := .cxx
LOCAL_ASSET_FILES
In Android.mk files that include $(BUILD_PACKAGE)
set this to the set of files you want built into your app. Usually:
LOCAL_ASSET_FILES += $(call find-subdir-assets)
LOCAL_C_INCLUDES
Additional directories to instruct C/C++ compilers to include the header files of it. The default header file search path is the LOCAL_PATH directory.
For e.g: LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/.. \
$(LOCAL_PATH)/include \
$(LOCAL_PATH)/../btcore/include \
$(LOCAL_PATH)/../hci/include \
$(LOCAL_PATH)/../include \
$(LOCAL_PATH)/../stack/include \
$(bluetooth_C_INCLUDES)
LOCAL_C_INCLUDES needs to be set before any flags containing LOCAL_CFLAGS/LOCAL_CPPFLAGS.
LOCAL_CFLAGS
This is optional compiler option to use when compiling C code files. This may be useful when you are specifying macro defination, additional include path or compilation options.
For e.g: LOCAL_CFLAGS += -DANDROID \
-Wall \
-DLIBUTILS_NATIVE=1\
LOCAL_CPPFLAGS
Same as LOCAL_CFLAGS, but applicable for both C/C++ files
LOCAL_SHARED_LIBRARIES
Same as LOCAL_STATIC_LIBRARIES, but here it only includes shared libraries that module depends on during runtime.
For e.g:
LOCAL_SHARED_LIBRARIES := \
libutils \
libui \
libaudio \
libexpat \
libsgl
LOCAL_CC
This will be used when you want to set different C compiler, rather than default.
LOCAL_FORCE_STATIC_EXECUTABLE
Set this to true, if you want to link your executable statically. This is only be used for executables running in /sbin, on the root of your file system.
For e.g: LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE_TAG
This flag is used to specify under what circumstances to compile your module. It could be optional/eng/test
For e.g:
LOCAL_MODULE_TAGS := optional
Means, To compile this module in all versions.
LOCAL_MODULE_TAGS := eng
Means, to compile this module only in development/engineering environment.
Same goes for
LOCAL_MODULE_TAGS := debug
Means. to compile only in debug environment
LOCAL_MODULE_TAGS := user
If the library or mudule is required only in final software product.
LOCAL_PROGUARD_ENABLED
This is to set the type of proguard you want to enable in your module(obfuscation,, optimazation or both).
For e.g:
LOCAL_PROGUARD_ENABLED := obfuscation
or
LOCAL_PROGUARD_ENABLED := obfuscation optimization
LOCAL_PROGUARD_FLAG_FILES
This is to include the proguard file.
For e.g:
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
LOCAL_PRIVILEGED_MODULE
This is to place the apk in the priv-app folder of the build. It could be either /system/priv-app/ or /vendor/priv-app/
For e.g:
LOCAL_PRIVILEGED_MODULE := true
LOCAL_VENDOR_MODULE
This is to place the apk in the /vendor/ directory
For e.g:
LOCAL_VENDOR_MODULE := true
LOCAL_MULTILIB
This is to tell the build system, that the module is limited to 32 bit or 64bit or it is compatible to both.
For e.g:
LOCAL_MULTILIB := 32/64/BOTH
LOCAL_REQUIRED_MODULES
This is to tell the build system, that your module needs the mentioned libraries to be build first.
For e.g:
LOCAL_REQUIRED_MODULES := SoundRecorder, AndroidLib
LOCAL_OVERRIDES_PACKAGES
This variable will override the package provided, with your current package/module. You need to provide the name of the module that you want to override to. For example you are creating your own app and want to override launcher3 app that is already present in the system.
Adding this flag to your Android.mk file will ensure that those packages are not added to any build where this package is added.
Use it like this:
LOCAL_OVERRIDES_PACKAGES := Home Launcher2 Launcher3
Fowllowing this call: make installclean
while building your android source. This will clean out your out directory of any old modules/images.
You can see it from this link how DeskClock is overriding the AlarmClock in AOSP.
GNU make ‘function’ macro in Android.mk
Now, let’s see some of the macro functions in action.
- all-subdir-makefiles: This will returns the list of all Android.mk files under the LOCAL_PATH or current directory.
For e.g: include $(call all-subdir-makefiles) - all-makefiles-under: This is to include all the make files under the given path in the macro.
For e.g: include $(call all-makefiles-under,$(LOCAL_PATH)) - all-java-files-under: This is to include all the JAVA files present in the given location.
For e.g: LOCAL_SRC_FILES := $(call all-java-files-under, src)
Where src is the directory under which Java files are present. - all-Iaidl-files-under: This is to include all AIDL files present in the given location.
For e.g: LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-Iaidl-files-under, src)
The original article was published in GizmoMind.com. You can follow the link.