My Avatar

Shilong ZHAO

Start Android Build Environment

2015-07-22 00:00:00 +0200

In case you have any questions or suggestions, you can leave comments HERE . Thanks!

It is assumed that you are familiar with Linux and Android. It will be very helpful if you are familiar with GNU toolchain (Autotools, Make, etc), since the concepts here in Android are quite comparable with that in Linux.

The first thing we need to do is make sure that all the dependent packages, including JDK, are installed and properly configured on your work station. Then download the Android source code. Detailed instructions are available on the Android site.

After these step have been done, go to the directory where Android source code is stored and run build/envsetup.sh

$ cd path/to/aosp
$ source build/envsetup.sh

including device/asus/deb/vendorsetup.sh
...
including device/generic/mini-emulator-arm64/vendorsetup.sh
including device/generic/mini-emulator-armv7-a-neon/vendorsetup.sh
...
including device/samsung/manta/vendorsetup.sh
including sdk/bash_completion/adb.bash

In these vendersetup.sh script files, there is actually only one line command, for example the effective contents in mini-emulator-arm64/vendorsetup.sh is simply

add_lunch_combo mini_emulator_arm64-userdebug

Function add_lunch_combo is defined in build/envsetup.sh and serves to check if a lunch combination has been added into LUNCH_MENU_CHOICES and if not, it will be appended to the menu:

function add_lunch_combo()
{
  local new_combo=$1
  local c
  for c in ${LUNCH_MENU_CHOICES[@]} ; do
    if [ "$new_combo" = "$c"] ; then
      return
    fi
  done
  LUNCH_MENU_CHOICES=(${LUNCH_MENU_CHOICES[@]} $new_combo)
}
# add the default one here
add_lunch_combo aosp_arm-eng
add_lunch_combo aosp_arm64-eng
...
add_lunch_combo aosp_x86_64-eng

But envsetup.sh does more than just adding lunch combinations, there are also some auxiliary functions to make life easier.

$ hmm

Invoke ". build/envsetup.sh" from your shell to add the following functions to your environment:
- lunch:   lunch <product_name>-<build_variant>
- tapas:   tapas [<App1> <App2> ...] [arm|x86|mips|armv5|arm64|x86_64|mips64] [eng|userdebug|user]
- croot:   Changes directory to the top of the tree.
- m:       Makes from the top of the tree.
- mm:      Builds all of the modules in the current directory, but not their dependencies.
- mmm:     Builds all of the modules in the supplied directories, but not their dependencies.
           To limit the modules being built use the syntax: mmm dir/:target1,target2.
- mma:     Builds all of the modules in the current directory, and their dependencies.
- mmma:    Builds all of the modules in the supplied directories, and their dependencies.
- cgrep:   Greps on all local C/C++ files.
...

If you are in a deep subdirectory under AOSP source tree, then running croot in shell will directly lead to path\to\aosp. We will see the usage of lunch immediately, and other commands like m, mm in the following parts.

Function lunch is also defined in envsetup.sh. It reads the choice, find the lunch combo, and in the end set environmental variables. The product is the the part before the dash - in a lunch combo, e.g. mini_emulator_arm64, and variant is the part after -, e.g. userdebug:

function lunch()
{
  ...
  answer=$1
  ...
  selection=${LUNCH_MENU_CHOICES[$(($answer-1))]}
  ...
  product=$(echo -n $selection | sed -e "s/-.*$//")
  ...
  variant=$(echo -n $selection | sed -e "s/^[^\-]*-//")
  ...
  export TARGET_PRODUCT=$product
  export TARGET_BUILD_VARIANT=$variant
  export TARGET_BUILD_TYPE=release
  ...
}

Type lunch in the terminal

$ lunch

You are building on Linux

Lunch menu... pick a combo:
     1. aosp_arm-eng
     2. aosp_arm64-eng
     ...
     6. aosp_x86_64-eng
     7. aosp_deb-userdebug
     ...
     13. mini_emulator_arm64-userdebug
     ...

Which would you like? [aosp_arm-eng]

Here all the lunch combinations previously added by add_lunch_combo are listed. Type the corresponding number of the build target you’ve chosen. If only press enter, aosp_arm-eng will be the default choice. A set of environmental varaibles will be set.

Which would you like? [aosp_arm-eng]
============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=5.0.1
TARGET_PRODUCT=aosp_arm
TARGET_BUILD_VARIANT=eng
TARGET_BUILD_TYPE=release
TARGET_BUILD_APPS=
TARGET_ARCH=arm
TARGET_ARCH_VARIANT=armv7-a
TARGET_CPU_VARIANT=generic
TARGET_2ND_ARCH=
TARGET_2ND_ARCH_VARIANT=
TARGET_2ND_CPU_VARIANT=
HOST_ARCH=x86_64
HOST_OS=linux
HOST_OS_EXTRA=Linux-3.10.0-229.7.2.el7.x86_64-x86_64-with-centos-7.1.1503-Core
HOST_BUILD_TYPE=release
BUILD_ID=LRX22C
OUT_DIR=out
============================================

PLATFORM_VERSION is the Android platform version, which is 5.0.1 or Lollipop. TARGET_BUILD_VARIANT is eng, so all the modules tagged with eng, user, debug will be installed. TARGET_ARCH is the target CPU architecture. All the build output will be put into OUT_DIR which is path/to/aosp/out.

$ env | grep ANDROID

ANDROID_DEV_SCRIPTS=path/to/aosp/development/scripts:path/to/aosp/prebuilts/devtools/tools
ANDROID_PRE_BUILD_PATHS=/usr/lib/jvm/java-7-openjdk-amd64/bin:
ANDROID_BUILD_TOP=path/to/aosp
ANDROID_PRODUCT_OUT=path/to/aosp/out/target/product/generic
ANDROID_JAVA_TOOLCHAIN=/usr/lib/jvm/java-7-openjdk-amd64/bin
ANDROID_BUILD_PATHS=path/to/aosp/out/host/linux-x86/bin:path/to/aosp/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8/bin:path/to/aosp/prebuilts/gcc/linux-x86/:path/to/aosp/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin:path/to/aosp/development/scripts:path/to/aosp/prebuilts/devtools/tools:path/to/aosp/prebuilts/android-emulator/linux-x86_64:
ANDROID_TOOLCHAIN=path/to/aosp/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8/bin
ANDROID_TOOLCHAIN_2ND_ARCH=path/to/aosp/prebuilts/gcc/linux-x86/
ANDROID_EMULATOR_PREBUILTS=path/to/aosp/prebuilts/android-emulator/linux-x86_64
ANDROID_HOST_OUT=path/to/aosp/out/host/linux-x86
ANDROID_SET_JAVA_HOME=true

ANDROID_BUILD_TOP is the root directory for Android source code. ANDROID_PRODUCT_OUT is where you will find all the built libraries. ANDROID_BUILD_TOOLCHAIN defines the toolchain that is gonna be used for compilation, linking, etc.

Now the environment is set up, and it’s time to build Android:

$ m -j16

Function m’s implementation is shown in the following code block. It calls make, change the directory to the source root, and use build/core/main.mk as the makefile, appending other user specified parameters, i.e. spawning 16 jobs in this case.

function m()
{
  local T=$(gettop)
  local DRV=$(getdriver $T)
  if [ "$T" ]; then
    $DRV make -C $T -f build/core/main.mk $@
  else
    echo "Couldn't locate the top of the tree. Try setting TOP."
  fi
}

It will take a long time to finish. After that you will have a customized Android image. You can start you own Android by

$ emulator &

Notice that every time when you close the terminal where you’ve configured the environment. You’ll have to rerun

$ source ./build/envsetup.sh
$ lunch

If you lunch the same configuration which you’ve built, there will be no need to run m -j16 anymore. However, if you want to build for a new target, say x86, you really have to run m -j16 once again.

In the next post I will write something about how to port libcurl to Android.