AOSP Foundations
3 min read

Android.mk Basics

Understand the fundamentals of Android.mk, the legacy Makefile-based build script that orchestrated early AOSP.

For the first decade of Android's existence, the entire operating system was built using GNU Make. While Google has since transitioned to a modern build system (Soong), understanding Android.mk is still a strict requirement for AOSP engineers because thousands of legacy hardware modules and third-party projects still use it today.

What is an Android.mk file?

An Android.mk file is a small text file written in the Make language. It sits alongside your C++, Java, or XML source code and tells the build system exactly what source files to compile, what libraries to link against, and what the final output should be (e.g., an APK, a shared library, or an executable).

When you run a build, the build system traverses the entire AOSP directory tree looking for every file named Android.mk and aggregates them into one massive, global Makefile.

The Standard Structure

Every standard Android.mk file follows a very strict, repetitive structure.

# 1. Define the local path (must be the first line)
LOCAL_PATH := $(call my-dir)

# 2. Clear previous global variables to ensure a clean state
include $(CLEAR_VARS)

# 3. Define source files, dependencies, and module name
LOCAL_SRC_FILES := main.cpp helper.cpp
LOCAL_SHARED_LIBRARIES := liblog libutils
LOCAL_MODULE := my_custom_binary

# 4. Invoke the build rule to generate an executable
include $(BUILD_EXECUTABLE)

1. LOCAL_PATH and my-dir

The very first line of almost every Android.mk must be:

LOCAL_PATH := $(call my-dir)

This macro function (my-dir) determines the exact physical directory path of the current Android.mk file. This is crucial because the build system executes from the root of the AOSP tree. Setting LOCAL_PATH allows you to reference your source files (main.cpp) relative to your current folder, rather than typing out the absolute path from the AOSP root.

2. Clearing Variables

Because Make parses all Android.mk files into a single global environment, variables are global by default. To prevent your module from accidentally inheriting a setting from someone else's module, you must explicitly clear the slate using include $(CLEAR_VARS).

3. Module Definition

This is where you define exactly what makes up your program.

  • LOCAL_MODULE: The unique name of your final output (e.g., if you name it libcustom, the output will be libcustom.so).
  • LOCAL_SRC_FILES: A list of all the source files to compile.
  • LOCAL_CFLAGS: Custom compiler flags you want to pass directly to GCC or Clang.

4. Build Rules

The final line tells the build system what to actually do with the variables you just defined. In this example, include $(BUILD_EXECUTABLE) tells the system to compile the source files and link them into a binary executable that can be run from the command line.

# You can test compiling a single legacy Android.mk module quickly using 'mm'
cd system/core/my_module
mm