267 lines
5.8 KiB
Bash
Executable File
267 lines
5.8 KiB
Bash
Executable File
#!/bin/bash -e
|
|
|
|
# Acquire lock on source tree
|
|
parent=$(ps h -o comm $PPID)
|
|
if [ "$parent" != "flock" ]; then
|
|
exec flock ".lock" $0 "$@"
|
|
fi
|
|
|
|
usage()
|
|
{
|
|
prog=$(basename $0)
|
|
|
|
echo ""
|
|
echo "Usage:"
|
|
echo " $prog [options] <build_combo>"
|
|
echo ""
|
|
echo " Options:"
|
|
echo " -a Automated build (check for clean working dir)"
|
|
echo " -c Clean output before build"
|
|
echo " Given once, clean device output (out/target/product)"
|
|
echo " Given twice, clean target output (out/target)"
|
|
echo " Given thrice, clean all output (out)"
|
|
echo " -C Clean output after successful build"
|
|
echo " Given once, clean device output (out/target/product)"
|
|
echo " Given twice, clean target output (out/target)"
|
|
echo " Given thrice, clean all output (out)"
|
|
echo " -j Specify -j value for make [CPUS]"
|
|
echo " -l Save build output to log file"
|
|
echo " -o Specify output directory"
|
|
echo " -O Specify Android out dir"
|
|
echo " -s Show commands"
|
|
echo " -t Specify make target [auto]"
|
|
echo " -v Specify version [none]"
|
|
echo ""
|
|
echo "Exit status: 0 on success, !0 on failure"
|
|
echo ""
|
|
echo "On success, output will be copied to \$TARGET_PRODUCT.zip."
|
|
echo ""
|
|
exit 1
|
|
}
|
|
|
|
# Tool locations
|
|
# XXX: not darwin compatible
|
|
CCACHE="prebuilts/misc/linux-x86/ccache/ccache"
|
|
|
|
ccache_stats()
|
|
{
|
|
# Calculate ccache stats
|
|
local ch=0
|
|
local cm=0
|
|
local ct=0
|
|
local cpct="NA"
|
|
|
|
OLDIFS="$IFS"
|
|
IFS=$'\n'
|
|
lines=($($CCACHE -s))
|
|
IFS="$OLDIFS"
|
|
for (( n=0; $n < ${#lines[*]}; n=$(($n+1)) )); do
|
|
line=${lines[$n]}
|
|
if [ "${line:0:9}" = "cache hit" ]; then
|
|
ch=$(( ch + $(echo $line | sed 's/[^0-9]*//') ))
|
|
elif [ "${line:0:10}" = "cache miss" ]; then
|
|
read -a fields <<<$line
|
|
cm=$(( cm + $(echo $line | sed 's/[^0-9]*//') ))
|
|
fi
|
|
done
|
|
IFS="$OLDIFS"
|
|
if [ -n "$ch" -a -n "$cm" ]; then
|
|
ct=$(($ch+$cm))
|
|
fi
|
|
if [ "$ct" -gt 0 ]; then
|
|
cpct=$((ch*100/ct))
|
|
fi
|
|
|
|
echo "ch=$ch"
|
|
echo "cm=$cm"
|
|
echo "ct=$ct"
|
|
echo "cpct=$cpct"
|
|
}
|
|
|
|
# Set some useful vars
|
|
export USE_CCACHE=1
|
|
export CPUS=$(grep "^processor" /proc/cpuinfo | wc -l)
|
|
export MEM=$(cat /proc/meminfo | grep "^MemTotal" | grep -o "[0-9]*")
|
|
|
|
# Find actual value for jobs.
|
|
# - No more than 8 jobs
|
|
# - No more than one job per cpu
|
|
# - No more than one job per 1.5gb
|
|
max_jobs=8
|
|
cpu_jobs="$CPUS"
|
|
if [ "$cpu_jobs" -lt "$max_jobs" ]; then
|
|
max_jobs="$cpu_jobs"
|
|
fi
|
|
mem_jobs=$(($MEM/1572864))
|
|
if [ "$mem_jobs" -lt "$max_jobs" ]; then
|
|
max_jobs="$mem_jobs"
|
|
fi
|
|
|
|
# Init options
|
|
opt_automated=0
|
|
opt_clean=0
|
|
opt_postclean=0
|
|
opt_jobs="$max_jobs"
|
|
opt_log=0
|
|
opt_outdir="."
|
|
opt_outandroid=""
|
|
opt_maketarget="auto"
|
|
opt_showcommands=0
|
|
opt_version=""
|
|
while getopts "acCj:lo:O:st:v:" opt; do
|
|
case "$opt" in
|
|
a) opt_automated=1 ;;
|
|
c) opt_clean=$(($opt_clean+1)) ;;
|
|
C) opt_postclean=$(($opt_postclean+1)) ;;
|
|
j) opt_jobs="$OPTARG" ;;
|
|
l) opt_log=1 ;;
|
|
o) opt_outdir="$OPTARG" ;;
|
|
O) opt_outandroid="$OPTARG" ;;
|
|
s) opt_showcommands=1 ;;
|
|
t) opt_maketarget="$OPTARG" ;;
|
|
v) opt_version="$OPTARG" ;;
|
|
*) usage
|
|
esac
|
|
done
|
|
shift $(($OPTIND-1))
|
|
if [ $# -ne 1 ]; then
|
|
usage
|
|
fi
|
|
|
|
if [ -n "$opt_outandroid" ]; then
|
|
export OUT_DIR_COMMON_BASE="$opt_outandroid"
|
|
fi
|
|
|
|
mkdir -p "$opt_outdir"
|
|
|
|
# NB: "$combo" is used by build scripts
|
|
build_combo="$1"
|
|
project_device=$(echo $build_combo | cut -d'-' -f1)
|
|
project=$(echo $project_device | cut -d'_' -f1)
|
|
device=$(echo $project_device | cut -d'_' -f2)
|
|
|
|
# Desired output files
|
|
if [ -n "$opt_version" ]; then
|
|
out_name="${opt_outdir}/${project_device}-${opt_version}"
|
|
else
|
|
out_name="${opt_outdir}/${project_device}"
|
|
fi
|
|
|
|
if [ "$opt_log" -ne 0 ]; then
|
|
rm -f "${out_name}.log"
|
|
exec >> "${out_name}.log" 2>&1
|
|
fi
|
|
|
|
if [ ! -d ".repo" ]; then
|
|
echo "Invalid build tree"
|
|
exit 1
|
|
fi
|
|
|
|
case "$opt_clean" in
|
|
0) # Do nothing
|
|
;;
|
|
1) # Clean device output
|
|
rm -rf "$OUT_DIR_COMMON_BASE/target/product"
|
|
;;
|
|
2) # Clean target output
|
|
rm -rf "$OUT_DIR_COMMON_BASE/target"
|
|
;;
|
|
*) # Clean all output
|
|
rm -rf "$OUT_DIR_COMMON_BASE"
|
|
;;
|
|
esac
|
|
|
|
# Detect make target
|
|
if [ -z "$opt_maketarget" -o "$opt_maketarget" = "auto" ]; then
|
|
opt_maketarget="otapackage"
|
|
if [ -f "build/core/Makefile" ]; then
|
|
if grep -q "^bacon:" "build/core/Makefile"; then
|
|
opt_maketarget="bacon"
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
if [ "$opt_showcommands" -ne 0 ]; then
|
|
opt_maketarget="showcommands $opt_maketarget"
|
|
fi
|
|
|
|
# Ensure working directory is clean
|
|
if [ "$opt_automated" -ne 0 ]; then
|
|
android-repo status | grep -q "working directory clean"
|
|
fi
|
|
|
|
. build/envsetup.sh
|
|
lunch "$build_combo"
|
|
|
|
# Setup ccache
|
|
if [ -z "$CCACHE_ROOT" ]; then
|
|
CCACHE_ROOT="$HOME"
|
|
fi
|
|
|
|
export CCACHE_DIR="$CCACHE_ROOT/.ccache-$project_device"
|
|
if [ ! -d "$CCACHE_DIR" ]; then
|
|
mkdir -p "$CCACHE_DIR"
|
|
$CCACHE -M 8G
|
|
fi
|
|
|
|
# Clean some things
|
|
rm -f $OUT/system/build.prop
|
|
|
|
eval $(ccache_stats)
|
|
sch=$ch
|
|
scm=$cm
|
|
sct=$ct
|
|
scpct=$cpct
|
|
|
|
# Do the build
|
|
stime=$(date +%s)
|
|
make -j${opt_jobs} ${opt_maketarget}
|
|
etime=$(date +%s)
|
|
|
|
# Find output zip
|
|
built_zip=$(ls -t $OUT/*.zip | head -1)
|
|
if [ ! -f "$built_zip" ]; then
|
|
echo "Error: cannot find built zip in $OUT"
|
|
exit 1
|
|
fi
|
|
|
|
# Copy output zip to well known place
|
|
cp "$built_zip" "${out_name}.zip"
|
|
|
|
# Calculate elapsed time
|
|
elapsedsec=$((etime - stime))
|
|
elapsed=$(printf "%02d:%02d" $((elapsedsec/60)) $((elapsedsec%60)))
|
|
|
|
eval $(ccache_stats)
|
|
ech=$ch
|
|
ecm=$cm
|
|
ect=$ct
|
|
ecpct=$cpct
|
|
|
|
dch=$((ech - sch))
|
|
dcm=$((ecm - scm))
|
|
dct=$((ect - sct))
|
|
dcpct="NA"
|
|
if [ "$dct" -gt 0 ]; then
|
|
dcpct=$((dch*100/dct))
|
|
fi
|
|
|
|
echo "Build complete."
|
|
echo "elapsed time : $elapsed"
|
|
echo "ccache totals: $ech/$ect ($ecpct%)"
|
|
echo "ccache deltas: $dch/$dct ($dcpct%)"
|
|
|
|
case "$opt_postclean" in
|
|
0) # Do nothing
|
|
;;
|
|
1) # Clean device output
|
|
rm -rf "$OUT_DIR_COMMON_BASE/target/product"
|
|
;;
|
|
2) # Clean target output
|
|
rm -rf "$OUT_DIR_COMMON_BASE/target"
|
|
;;
|
|
*) # Clean all output
|
|
rm -rf "$OUT_DIR_COMMON_BASE"
|
|
;;
|
|
esac
|