Last active
October 16, 2019 01:33
-
-
Save MartinMReed/b5e8a56651fd25569ff3 to your computer and use it in GitHub Desktop.
Compile AOSP (Android Open Source Project) on macOS
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /bin/sh | |
# | |
# Build directory: | |
BUILD_DIRECTORY=~/Desktop | |
# | |
# | |
# | |
# Each build of AOSP is tied to a specific source tag. You can find the match between the | |
# build number and source tag from the link below. If you choose a tag that does not properly | |
# match with the build number, you will receive a warning prompt when running this script. | |
# You will have the option to continue using the mismatch tag, however that is not recommended. | |
# https://source.android.com/source/build-numbers.html#source-code-tags-and-builds | |
# All possible AOSP tags and branches can be found at: | |
# https://android.googlesource.com/platform/manifest/+refs | |
ANDROID_BUILD= | |
ANDROID_VERSION= | |
ANDROID_DEVICE= | |
# | |
# | |
# | |
# The vendor drivers necessary for a build will be downloaded by this script, however the | |
# hash of each driver needs to be provided here. The drivers are provided by Google at: | |
# https://developers.google.com/android/nexus/drivers | |
# The URL will be in the form of: | |
# https://dl.google.com/dl/android/aosp/<vendor>-<device>-<build>-<hash>.tgz | |
# Example usage: | |
# declare driver_asus=<hash> | |
# declare driver_broadcom=<hash> | |
# declare driver_qcom=<hash> | |
# | |
# VENDORS=(google_devices nvidia broadcom lge qcom asus) | |
# for VENDOR in "${VENDORS[@]}"; do declare driver_${VENDOR}=; done | |
# | |
# | |
# | |
# Nexus 7 (old, mobile), OS 5.1.1 | |
ANDROID_BUILD=lmy47v | |
ANDROID_VERSION=5.1.1_r1 | |
ANDROID_DEVICE=tilapia | |
VENDORS=(asus broadcom elan invensense nvidia nxp widevine) | |
declare driver_asus=6272610e | |
declare driver_broadcom=e9d05927 | |
declare driver_elan=5f509df5 | |
declare driver_invensense=066fff5f | |
declare driver_nvidia=05744cf3 | |
declare driver_nxp=7a361708 | |
declare driver_widevine=2844d74a | |
if [ "$(uname)" != "Darwin" ]; then | |
echo "This script is intended to run on macOS" | |
exit 1 | |
fi | |
_SCRIPT_PATH="$(cd $(dirname ${BASH_SOURCE[0]}) && pwd)/${BASH_SOURCE[0]}" | |
function err_trap { | |
echo "------------------------------------------------" | |
echo "Error occurred on line ${_SCRIPT_LINENO}:" | |
echo " ${_SCRIPT_COMMAND}" | |
echo "------------------------------------------------" | |
exit $1 | |
} | |
function debug_trap { | |
# "fi" at the end of an if-block will result in BASH_COMMAND="return $ret" | |
if [ "$2" != "return \$ret" ]; then _SCRIPT_LINENO="$1"; _SCRIPT_COMMAND="$2"; fi | |
} | |
trap 'err_trap "$?"' ERR | |
trap 'debug_trap "${LINENO}" "${BASH_COMMAND}"' DEBUG | |
# Necessary for using a map in Bash 3 | |
array_get() { | |
local i="$1_$2" | |
printf '%s' "${!i}" | |
} | |
OPT_ENABLE_SYNC=1 | |
OPT_ENABLE_MAKE=1 | |
OPT_ENABLE_REMAKE= | |
while test $# -gt 0; do | |
case "$1" in | |
--nosync) OPT_ENABLE_SYNC=;; | |
--nomake) OPT_ENABLE_MAKE=;; | |
--remake) OPT_ENABLE_REMAKE=1;; | |
--*) echo "Bad option $1"; exit 1;; | |
*) echo "Bad argument $1"; exit 1;; | |
esac | |
shift | |
done | |
if [ -z "$OPT_ENABLE_SYNC" ]; then | |
echo "SYNC has been disabled" | |
fi | |
if [ -z "$OPT_ENABLE_MAKE" ]; then | |
echo "MAKE has been disabled" | |
elif [ ! -z "$OPT_ENABLE_REMAKE" ]; then | |
echo "REMAKE has been enabled" | |
fi | |
# TOOLCHAINS | |
# | |
# Verify that the necessary tools are available. | |
# If some are missing, you can install through Homebrew. | |
# | |
function toolchain_require() { which $1 &> /dev/null; return $?; } | |
# | |
toolchain_require make | |
toolchain_require wget | |
toolchain_require git | |
toolchain_require java | |
toolchain_require gunzip | |
toolchain_require tar | |
toolchain_require python | |
toolchain_require curl | |
toolchain_require xcodebuild | |
# | |
# | |
ANDROID_VERSION_MAJOR=$(echo "${ANDROID_VERSION}" | sed -n 's/\([0-9]*\)\.\([0-9]*\)\(\.[0-9]*\)*_r[0-9]*/\1/p') | |
ANDROID_VERSION_MINOR=$(echo "${ANDROID_VERSION}" | sed -n 's/\([0-9]*\)\.\([0-9]*\)\(\.[0-9]*\)*_r[0-9]*/\2/p') | |
# CURL | |
# | |
if [[ ! -z "$(curl --version | grep SecureTransport)" ]]; then echo "Curl must be compiled with OpenSSL instead of SecureTransport. Please see details at $0:${LINENO}."; exit 1; fi | |
# | |
# While compiling, if you receive an error about cURL, you may need to install the version from brew. | |
# | |
# > Unsupported curl, please use a curl not based on SecureTransport | |
# | |
# $ brew install curl --with-openssl | |
# | |
# | |
if [[ ! -z "$(brew --prefix curl)" ]]; then | |
PATH=$(brew --prefix curl)/bin:$PATH | |
fi | |
# | |
# | |
# ERROR BUILDING: BOOT.IMG | |
# | |
if [[ ! -f "/usr/local/lib/libcrypto.1.0.0.dylib" ]]; then echo "libcrypto is expected under /usr/local/lib. Please see details at $0:${LINENO}."; exit 1; fi | |
if [[ ! -f "/usr/local/lib/libssl.1.0.0.dylib" ]]; then echo "libssl is expected under /usr/local/lib. Please see details at $0:${LINENO}."; exit 1; fi | |
# | |
# > dyld: Library not loaded: /opt/local/lib/libcrypto.1.0.0.dylib | |
# | |
# $ brew uninstall --ignore-dependencies --force openssl | |
# $ brew install openssl | |
# $ ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/ | |
# $ ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/ | |
# | |
# | |
# XCODE | |
# | |
# LATEST_XCODE_SDK=$(basename "$(xcrun --show-sdk-path)" | sed -n 's/MacOSX\(.*\)\.sdk/\1/p') | |
# | |
# You can check supported versions: cat workspace/build/core/combo/mac_version.mk | grep mac_sdk_versions_supported | |
if (( "${ANDROID_VERSION_MAJOR}" >= "7" )); then MACOS_SDK="10.11"; | |
elif (( "${ANDROID_VERSION_MAJOR}" >= "6" )); then MACOS_SDK="10.9"; | |
elif (( "${ANDROID_VERSION_MAJOR}" >= "5" )); then MACOS_SDK="10.9"; | |
elif (( $(echo "${ANDROID_VERSION_MAJOR}.${ANDROID_VERSION_MINOR} >= 4.1" | bc -l) )); then MACOS_SDK="10.9"; | |
else MACOS_SDK="10.9"; fi | |
# | |
#XCODE_SDK_PATH=$(dirname "$(xcrun --show-sdk-path 2>/dev/null)") | |
#if [[ ! -d "${XCODE_SDK_PATH}/MacOSX${MACOS_SDK}.sdk" ]]; then echo "macOS SDK ${MACOS_SDK} expected. Please see details at $0:${LINENO}."; exit 1; fi | |
# | |
if [[ -z "$(xcodebuild -showsdks | grep macosx${MACOS_SDK})" ]]; then echo "macOS SDK ${MACOS_SDK} expected. Please see details at $0:${LINENO}."; exit 1; fi | |
# | |
# XCode has a minimum SDK requirement and will ignore older SDK installs. Therefore you may also need an older version of XCode. | |
# Once downloaded, use xcode-select to switch to it: | |
# | |
# $ sudo xcode-select --switch /Applications/Xcode-5.0.2.app/Contents/Developer | |
# | |
# | |
# The required macOS SDK may be available through this repo (i.e. MacOSX10.11.sdk.tar.xz) | |
# | |
# $ sudo mv MacOSX10.11.sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/ | |
# $ sudo chown root:wheel /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs | |
# | |
# Other MacOSX SDK are available through Github: | |
# https://github.com/phracker/MacOSX-SDKs/releases | |
# | |
# | |
# JAVA | |
# | |
if (( "${ANDROID_VERSION_MAJOR}" >= "7" )); then JAVA_SDK="1.8"; | |
elif (( "${ANDROID_VERSION_MAJOR}" >= "6" )); then JAVA_SDK="1.7"; | |
elif (( "${ANDROID_VERSION_MAJOR}" >= "5" )); then JAVA_SDK="1.7"; | |
elif (( $(echo "${ANDROID_VERSION_MAJOR}.${ANDROID_VERSION_MINOR} >= 2.3" | bc -l) )); then JAVA_SDK="1.6"; | |
else JAVA_SDK="1.5"; fi | |
# | |
export JAVA_HOME=$(/usr/libexec/java_home -v ${JAVA_SDK}) | |
JAVA_VER=$(java -version 2>&1 | sed 's/java version "\(.*\)\.\(.*\)\..*"/\1.\2/; 1q') | |
if [ "${JAVA_VER}" != "${JAVA_SDK}" ]; then echo "java ${JAVA_SDK} expected. Please see details at $0:${LINENO}."; exit 1; fi | |
# | |
export PATH=$JAVA_HOME/bin:$PATH | |
# | |
# For some older Android OS you may need an lower JAVA version. | |
# Check requirements here: https://source.android.com/source/requirements.html | |
# | |
# To see current installed versions, look under /Library/Java/JavaVirtualMachines/ | |
# If you do not have what you need, you can install using HomeBrew. | |
# See http://stackoverflow.com/a/29195815/2616171 | |
# | |
# $ brew tap caskroom/versions | |
# $ brew cask search java | |
# $ brew cask install java6 | |
# | |
# | |
# BUILD + TAG VALIDATION | |
# | |
# | |
EXPECTED_BRANCH_CMD="import re | |
build_number = '${ANDROID_BUILD}'.upper() | |
pattern = r'.*<tr>\s*<td>(' + build_number + r')</td>\s*<td>android-([^<]*)</td>\s*<td>([^<]*)</td>\s*<td>([^<]*)</td>\s*</tr>.*' | |
output = \"\"\"$(curl --silent https://source.android.com/source/build-numbers.html)\"\"\" | |
matcher = re.search(pattern, output) | |
print(matcher.group(2))" | |
EXPECTED_BRANCH=$(python -c "${EXPECTED_BRANCH_CMD}") | |
if [ "${EXPECTED_BRANCH}" != "${ANDROID_VERSION}" ]; then | |
echo "The expected tag for build ${ANDROID_BUILD} is ${EXPECTED_BRANCH}, but ${ANDROID_VERSION} was selected." | |
while true; do | |
read -p "Continue using ${ANDROID_VERSION} anyway? [yN] " yn | |
case $yn in | |
[Yy]* ) break;; | |
* ) echo "exiting..."; exit 1;; | |
esac | |
done | |
fi | |
# | |
# | |
# DRIVER DOWNLOAD VALIDATION | |
# | |
# | |
for VENDOR in "${VENDORS[@]}"; do | |
DRIVER_HASH=$(array_get driver ${VENDOR}) | |
if [ ! -z "${DRIVER_HASH}" ]; then | |
DRIVER_FILENAME="${VENDOR}-${ANDROID_DEVICE}-${ANDROID_BUILD}-${DRIVER_HASH}" | |
DRIVER_URL="https://dl.google.com/dl/android/aosp/${DRIVER_FILENAME}.tgz" | |
curl --output /dev/null --silent --head --fail "${DRIVER_URL}" | |
if [ "$?" != "0" ]; then echo "url not found: ${DRIVER_URL}"; exit 1; fi | |
fi | |
done | |
# | |
# | |
# VOLUME CREATION AND AVAILABILITY | |
# | |
# | |
VOLUME_SPACE_REQUIRED=100 | |
VOLUME_SPACE_AVAILABLE=$(( $(df -k ${BUILD_DIRECTORY} | tail -1 | awk '{print $4}') / 1024 / 1024 )) | |
if (( "${VOLUME_SPACE_REQUIRED}" > "${VOLUME_SPACE_AVAILABLE}" )); then echo "Requires ${VOLUME_SPACE_REQUIRED}GB, but only ${VOLUME_SPACE_AVAILABLE}GB is available. Please see details at $0:${LINENO}."; exit 1; fi | |
# | |
# | |
VOLUME=android-${ANDROID_DEVICE}_${ANDROID_BUILD}-${ANDROID_VERSION} | |
VOLUME_DMG=${BUILD_DIRECTORY}/${VOLUME}.dmg | |
# | |
# Create the volume DMG file that will provide the necessary filesystem type | |
if [ ! -f "${VOLUME_DMG}" ]; then | |
hdiutil create -volname "${VOLUME}" -fs "Case-sensitive Journaled HFS+" -size ${BUILD_SPACE_REQUIRED}GB ${VOLUME_DMG} | |
if [ ! -f "${VOLUME_DMG}" ]; then echo "Could not create ${VOLUME_DMG}"; exit 1; fi | |
fi | |
# | |
# Check which volume path should be used. If attached manually, it will be in a different location. | |
if [ -d "/Volumes/${VOLUME}" ]; then | |
BIN=/Volumes/${VOLUME} | |
else | |
BIN=${BUILD_DIRECTORY}/${VOLUME} | |
fi | |
# | |
# Attach the volume if it is not already available | |
if [ ! -d "${BIN}" ]; then | |
hdiutil attach ${VOLUME_DMG} -mountroot ${BUILD_DIRECTORY} | |
if [ ! -d "${BIN}" ]; then echo "Could not open ${BIN}"; exit 1; fi | |
fi | |
# | |
# | |
WORKING_DIRECTORY=${BIN}/workspace | |
PATH=${BIN}:$PATH | |
# Download the latest version of the REPO tool | |
if [ ! -f "${BIN}/repo" ]; then | |
curl https://storage.googleapis.com/git-repo-downloads/repo > ${BIN}/repo | |
if [ ! -f "${BIN}/repo" ]; then echo "Could not create ${BIN}/repo"; exit 1; fi | |
fi | |
# Ensure that REPO is executable | |
if [ ! -x "${BIN}/repo" ]; then | |
chmod a+x ${BIN}/repo | |
if [ ! -x "${BIN}/repo" ]; then echo "Could not make ${BIN}/repo executable"; exit 1; fi | |
fi | |
# Create an empty directory to hold your working files | |
if [ ! -d "${WORKING_DIRECTORY}" ]; then | |
mkdir ${WORKING_DIRECTORY} | |
if [ ! -d "${WORKING_DIRECTORY}" ]; then echo "Could not open ${WORKING_DIRECTORY}"; exit 1; fi | |
fi | |
cd ${WORKING_DIRECTORY} | |
# Initialize the local REPO files using the remote manifest | |
if [ ! -d ".repo" ]; then | |
repo init -u https://android.googlesource.com/platform/manifest -b android-${ANDROID_VERSION} | |
if [ "$?" != "0" ]; then echo "Could not initialize repo"; rm -rf .repo; exit $?; fi | |
if [ ! -d ".repo" ]; then echo "Could not open ${WORKING_DIRECTORY}/.repo"; exit 1; fi | |
fi | |
# Synchronize all projects listed in the REPO manifest | |
if [ ! -z "$OPT_ENABLE_SYNC" ]; then | |
repo sync -j$(expr 2 \* $(sysctl hw.ncpu | awk '{print $2}')) | |
if [ "$?" != "0" ]; then echo "Syncing the repo projects has failed"; exit $?; fi | |
fi | |
# VENDOR DRIVER DOWNLOAD AND EXTRACTION | |
# | |
if [ ! -d "${BIN}/drivers" ]; then | |
mkdir ${BIN}/drivers | |
if [ ! -d "${BIN}/drivers" ]; then echo "Could not open ${BIN}/drivers"; exit 1; fi | |
fi | |
# | |
# | |
for VENDOR in "${VENDORS[@]}"; do | |
DRIVER_HASH=$(array_get driver ${VENDOR}) | |
if [ ! -z "${DRIVER_HASH}" ] && [ ! -d "./vendor/${VENDOR}/${ANDROID_DEVICE}/proprietary" ]; then | |
DRIVER_FILENAME="${VENDOR}-${ANDROID_DEVICE}-${ANDROID_BUILD}-${DRIVER_HASH}" | |
if [ ! -f "${BIN}/drivers/${DRIVER_FILENAME}.tgz" ]; then | |
DRIVER_URL="https://dl.google.com/dl/android/aosp/${DRIVER_FILENAME}.tgz" | |
wget -O ${BIN}/drivers/${DRIVER_FILENAME}.tgz ${DRIVER_URL} | |
if [ ! -f "${BIN}/drivers/${DRIVER_FILENAME}.tgz" ]; then echo "Could not download ${DRIVER_URL}"; exit 1; fi | |
fi | |
if [ ! -f "./extract-${VENDOR}-${ANDROID_DEVICE}.sh" ]; then | |
gunzip -c ${BIN}/drivers/${DRIVER_FILENAME}.tgz | tar xopf - | |
if [ ! -f "./extract-${VENDOR}-${ANDROID_DEVICE}.sh" ]; then echo "Could not create ${WORKING_DIRECTORY}/extract-${VENDOR}-${ANDROID_DEVICE}.sh"; exit 1; fi | |
fi | |
# User expect to auto-accept all license prompts that will come up from these driver scripts | |
expect -c ' | |
spawn sh ./extract-'${VENDOR}'-'${ANDROID_DEVICE}'.sh; | |
expect { | |
"Press Enter to view the license" { exp_send "\rq" ; exp_continue } | |
"Type \"I ACCEPT\" if you agree to the terms of the license:" { exp_send "I ACCEPT\r" ; exp_continue } | |
eof | |
}' | |
fi | |
done | |
# | |
# | |
. build/envsetup.sh | |
# LUNCH (build target selection) | |
# | |
# For some reason calling 'lunch' from a script is failing, so call the necessary parts directly. | |
# See https://android.googlesource.com/platform/build/+/jb-mr1.1-dev-plus-aosp/envsetup.sh | |
# | |
# lunch aosp_${ANDROID_DEVICE}-userdebug | |
# | |
# choosetype debug | |
# chooseproduct aosp_${ANDROID_DEVICE} | |
# choosevariant userdebug | |
choosecombo debug aosp_${ANDROID_DEVICE} userdebug | |
# | |
if [ "$?" != "0" ]; then echo "Unable to set product and variant. Please see details at $0:${LINENO}." exit $?; fi | |
# | |
# export TARGET_PRODUCT=aosp_${ANDROID_DEVICE} | |
# export TARGET_BUILD_VARIANT=userdebug | |
# export TARGET_BUILD_TYPE=debug | |
# set_stuff_for_environment | |
# printconfig | |
# OUT OF MEMORY | |
# | |
# > GC overhead limit exceeded. | |
# > Try increasing heap size with java option '-Xmx<size>'. | |
export ANDROID_JACK_VM_ARGS="-Dfile.encoding=UTF-8 -XX:+TieredCompilation -Xmx4g" | |
./prebuilts/sdk/tools/jack-admin kill-server 2>/dev/null || true | |
# ./prebuilts/sdk/tools/jack-admin start-server | |
if [ ! -z "$OPT_ENABLE_MAKE" ]; then | |
if [ ! -z "$OPT_ENABLE_REMAKE" ]; then | |
make clobber | |
fi | |
make -j$(expr 2 \* $(sysctl hw.ncpu | awk '{print $2}')) | |
# Generate IDE files | |
if [ -f "out/host/darwin-x86/framework/idegen.jar" ]; then | |
if [ ! -f "android.ipr" ]; then | |
mmm development/tools/idegen/ | |
development/tools/idegen/idegen.sh | |
fi | |
fi | |
fi | |
echo | |
echo "Complete: ${VOLUME}" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment