Home | History | Annotate | Download | only in distrib
      1 #!/bin/bash
      2 
      3 # This script is used to rebuild all emulator binaries from sources
      4 # and package them for easier distribution.
      5 
      6 set -e
      7 export LANG=C
      8 export LC_ALL=C
      9 
     10 PROGDIR=$(dirname "$0")
     11 PROGNAME=$(basename "$0")
     12 
     13 panic () {
     14   echo "ERROR: $@"
     15   exit 1
     16 }
     17 
     18 VERBOSE=1
     19 
     20 # Dump a message if VERBOSE is greater or equal to $1
     21 # $1: level
     22 # $2+: Message to print.
     23 dump_n () {
     24     local LEVEL=$1
     25     shift
     26     if [ "$VERBOSE" -ge "$LEVEL" ]; then
     27         printf "%s\n" "$@"
     28     fi
     29 }
     30 
     31 # Dump a message at VERBOSE level 1 (the default one).
     32 dump () {
     33     dump_n 1 "$@"
     34 }
     35 
     36 # Dump a message at VERBOSE level 2 (if --verbose was used).
     37 log () {
     38     dump_n 2 "$@"
     39 }
     40 
     41 # Run a command, dump its output depending on VERBOSE level, i.e.:
     42 #  0 -> Don't display anything.
     43 #  1 -> Display error messages only.
     44 #  2 -> Display the command, its output and error.
     45 run () {
     46     case $VERBOSE in
     47         0)
     48             "$@" >/dev/null 2>&1
     49             ;;
     50         1)
     51             "$@" >/dev/null
     52             ;;
     53         *)
     54             echo "COMMAND: $@"
     55             "$@"
     56             ;;
     57     esac
     58 }
     59 
     60 # Same as 'run', but slightly more quiet:
     61 #  0 or 1 -> Don't display anything
     62 #  2      -> Diplay the command, its output and error.
     63 run2 () {
     64     case $VERBOSE in
     65         0|1)
     66             "$@" >/dev/null 2>&1
     67             ;;
     68         2)
     69             echo "COMMAND: $@"
     70             "$@" >/dev/null 2>&1
     71             ;;
     72         *)
     73             echo "COMMAND: $@"
     74             "$@"
     75             ;;
     76     esac
     77 }
     78 
     79 # $1: Source directory.
     80 # $2: Destination directory.
     81 # $3: List of files to copy, relative to $1 (if empty, all files will be copied).
     82 copy_directory_files () {
     83   local SRCDIR DSTDIR FILES
     84   SRCDIR=$1
     85   DSTDIR=$2
     86   shift; shift;
     87   FILES="$@"
     88 
     89   mkdir -p "$DSTDIR" || panic "Cannot create destination directory: $DSTDIR"
     90   (cd $SRCDIR && tar cf - $FILES) | (cd $DSTDIR && tar xf -)
     91 }
     92 
     93 # $1: Source directory (must be a git checkout).
     94 # $2: Destination directory.
     95 copy_directory_git_files () {
     96   local SRCDIR DSTDIR FILES
     97   SRCDIR=$1
     98   DSTDIR=$2
     99   log "Copying git sources from $SRCDIR to $DSTDIR"
    100   # The list of names can contain spaces, so put them in a file to avoid
    101   # any issues.
    102   TMP_FILE_LIST=$(mktemp)
    103   (cd $SRCDIR && git ls-files) > $TMP_FILE_LIST
    104   mkdir -p "$DSTDIR" || panic "Cannot create destination directory: $DSTDIR"
    105   (cd $SRCDIR && tar cf - -T $TMP_FILE_LIST) | (cd $DSTDIR && tar xf -)
    106   rm -f $TMP_FILE_LIST
    107 }
    108 
    109 # Convert a comma-separated list into a space-separated one.
    110 commas_to_spaces () {
    111   printf "%s" "$@" | tr ',' ' '
    112 }
    113 
    114 # Rebuild Darwin binaries remotely through SSH
    115 # $1: Host name.
    116 # $2: Source package file.
    117 build_darwin_binaries_on () {
    118   local HOST PKG_FILE PKG_FILE_BASENAME DST_DIR TARFLAGS
    119   HOST=$1
    120   PKG_FILE=$2
    121 
    122   # The package file is ....../something-darwin.tar.bz2
    123   # And should unpack to a single directory named 'something/'
    124   # so extract the prefix from the package name.
    125   PKG_FILE_BASENAME=$(basename "$PKG_FILE")
    126   PKG_FILE_PREFIX=${PKG_FILE_BASENAME%%-sources.tar.bz2}
    127   if [ "$PKG_FILE_PREFIX" = "$PKG_FILE_BASENAME" ]; then
    128     # Sanity check.
    129     panic "Can't get package prefix from $PKG_FILE_BASENAME"
    130   fi
    131 
    132   # Where to do the work on the remote host.
    133   DST_DIR=/tmp/android-emulator-build
    134 
    135   if [ "$VERBOSE" -ge 3 ]; then
    136     TARFLAGS="v"
    137   fi
    138   dump "Copying sources to Darwin host: $HOST"
    139   run ssh $HOST "mkdir -p $DST_DIR && rm -rf $DST_DIR/$PKG_FILE_BASENAME"
    140   cat "$PKG_FILE" | ssh $HOST "cd $DST_DIR && tar x${TARGFLAGS}f -"
    141 
    142   dump "Rebuilding Darwin binaries remotely."
    143   run ssh $HOST "bash -l -c \"cd $DST_DIR/$PKG_FILE_PREFIX/qemu && ./android-rebuild.sh $REBUILD_FLAGS\"" ||
    144         panic "Can't rebuild binaries on Darwin, use --verbose to see why!"
    145 
    146   dump "Retrieving Darwin binaries from: $HOST"
    147   rm -rf objs/*
    148   run scp $HOST:$DST_DIR/$PKG_FILE_PREFIX/qemu/objs/emulator* objs/
    149   run scp -r $HOST:$DST_DIR/$PKG_FILE_PREFIX/qemu/objs/lib objs/lib
    150   # TODO(digit): Retrieve PC BIOS files.
    151   run ssh $HOST rm -rf $DST_DIR/$PKG_FILE_PREFIX
    152 }
    153 
    154 # Extract the git commit SHA1 of a given directory, and put its value
    155 # in a destination variable. If the target directory is not the root
    156 # of a git checkout, abort.
    157 # $1: Destination variable name.
    158 # $2: Git directory.
    159 # Example:   extract_commit_description GTEST_DESC "$GTEST_DIR"
    160 extract_git_commit_description () {
    161     local VARNAME GIT_DIR SHA1
    162     VARNAME=$1
    163     GIT_DIR=$2
    164     # Extract the commit description, then escape (') characters in it.
    165     SHA1=$(cd $GIT_DIR && git log --oneline -1 .) || \
    166         panic "Not a Git directory: $GIT_DIR"
    167 
    168     SHA1=$(printf "%s" "$SHA1" | sed -e "s/'/\\'/g")
    169     eval $VARNAME=\'$SHA1\'
    170 }
    171 
    172 # Defaults.
    173 DEFAULT_REVISION=$(date +%Y%m%d)
    174 DEFAULT_PKG_PREFIX=android-emulator
    175 DEFAULT_PKG_DIR=/tmp
    176 DEFAULT_DARWIN_SSH=$ANDROID_EMULATOR_DARWIN_SSH
    177 
    178 case $(uname -s) in
    179     Linux)
    180         DEFAULT_SYSTEMS="linux,windows"
    181         HOST_SYSTEM=linux
    182         ;;
    183     Darwin)
    184         DEFAULT_SYSTEMS="darwin"
    185         HOST_SYSTEM=darwin
    186         ;;
    187     *)
    188         panic "Unsupported system! This can only run on Linux and Darwin."
    189 esac
    190 
    191 # Command-line parsing.
    192 DO_HELP=
    193 OPT_COPY_PREBUILTS=
    194 OPT_DARWIN_SSH=
    195 OPT_PKG_DIR=
    196 OPT_PKG_PREFIX=
    197 OPT_REVISION=
    198 OPT_SOURCES=
    199 OPT_SYSTEM=
    200 
    201 for OPT; do
    202     case $OPT in
    203         --help|-?)
    204             DO_HELP=true
    205             ;;
    206         --copy-prebuilts=*)
    207             OPT_COPY_PREBUILTS=${OPT##--copy-prebuilts=}
    208             ;;
    209         --darwin-ssh=*)
    210             OPT_DARWIN_SSH=${OPT##--darwin-ssh=}
    211             ;;
    212         --package-dir=*)
    213             OPT_PKG_DIR=${OPT##--package-dir=}
    214             ;;
    215         --package-prefix=*)
    216             OPT_PKG_PREFIX=${OPT##--package-prefix=}
    217             ;;
    218         --quiet)
    219             VERBOSE=$(( $VERBOSE - 1 ))
    220             ;;
    221         --sources)
    222             OPT_SOURCES=true
    223             ;;
    224         --revision=*)
    225             OPT_REVISION=${OPT##--revision=}
    226             ;;
    227         --system=*)
    228             OPT_SYSTEM=${OPT##--system=}
    229             ;;
    230         --verbose)
    231             VERBOSE=$(( $VERBOSE + 1 ))
    232             ;;
    233         -*)
    234             panic "Unsupported option '$OPT', see --help."
    235             ;;
    236         *)
    237             panic "Unsupported parameter '$OPT', see --help."
    238     esac
    239 done
    240 
    241 if [ "$DO_HELP" ]; then
    242     cat <<EOF
    243 Usage: $PROGNAME [options]
    244 
    245 Rebuild the emulator binaries from source and package them into tarballs
    246 for easier distribution.
    247 
    248 New packages are placed by default at $DEFAULT_PKG_DIR
    249 Use --package-dir=<path> to use another output directory.
    250 
    251 Packages names are prefixed with $DEFAULT_PKG_PREFIX-<revision>, where
    252 the <revision> is the current ISO date by default. You can use
    253 --package-prefix=<prefix> and --revision=<revision> to change this.
    254 
    255 Binary packages will include the OpenGLES emulation libraries if they can
    256 be found in your current workspace, not otherwise.
    257 
    258 Use --sources option to also generate a source tarball.
    259 
    260 Use --darwin-ssh=<host> to build perform a remote build of the Darwin
    261 binaries on a remote host through ssh. Note that this forces --sources
    262 as well. You can also define ANDROID_EMULATOR_DARWIN_SSH in your
    263 environment to setup a default value for this option.
    264 
    265 Use --copy-prebuilts=<path> to specify the path of an AOSP workspace/checkout,
    266 and to copy 64-bit prebuilt binaries to <path>/prebuilts/android-emulator/
    267 for both Linux and Darwin platforms. This option requires the use of
    268 --darwin-ssh=<host> or ANDROID_EMULATOR_DARWIN_SSH to build the Darwin
    269 binaries.
    270 
    271 Valid options (defaults are inside brackets):
    272     --help | -?           Print this message.
    273     --package-dir=<path>  Change package output directory [$DEFAULT_PKG_DIR].
    274     --revision=<name>     Change revision [$DEFAULT_REVISION].
    275     --sources             Also create sources package.
    276     --system=<list>       Specify host system list [$DEFAULT_SYSTEMS].
    277     --copy-prebuilts=<path>  Copy 64-bit Linux and Darwin binaries to
    278                              <path>/prebuilts/android-emulator/
    279 
    280 EOF
    281     exit 0
    282 fi
    283 
    284 if [ "$OPT_PKG_PREFIX" ]; then
    285     PKG_PREFIX=$OPT_PKG_PREFIX
    286 else
    287     PKG_PREFIX=$DEFAULT_PKG_PREFIX
    288     log "Auto-config: --package-prefix=$PKG_PREFIX"
    289 fi
    290 
    291 if [ "$OPT_REVISION" ]; then
    292     PKG_REVISION=$OPT_REVISION
    293 else
    294     PKG_REVISION=$DEFAULT_REVISION
    295     log "Auto-config: --revision=$PKG_REVISION"
    296 fi
    297 
    298 if [ "$OPT_PKG_DIR" ]; then
    299     PKG_DIR=$OPT_PKG_DIR
    300     mkdir -p "$PKG_DIR" || panic "Can't create directory: $PKG_DIR"
    301 else
    302     PKG_DIR=$DEFAULT_PKG_DIR
    303     log "Auto-config: --package-dir=$PKG_DIR"
    304 fi
    305 
    306 if [ "$OPT_SYSTEM" ]; then
    307     SYSTEMS=$(commas_to_spaces $OPT_SYSTEM)
    308 else
    309     SYSTEMS=$(commas_to_spaces $DEFAULT_SYSTEMS)
    310     log "Auto-config: --system=$SYSTEMS"
    311 fi
    312 
    313 if [ -z "$OPT_DARWIN_SSH" ]; then
    314   DARWIN_SSH=$DEFAULT_DARWIN_SSH
    315   if [ "$DARWIN_SSH" ]; then
    316     log "Auto-config: --darwin-ssh=$DARWIN_SSH  (from environment)."
    317   fi
    318 else
    319   DARWIN_SSH=$OPT_DARWIN_SSH
    320 fi
    321 
    322 if [ "$DARWIN_SSH" ]; then
    323     if [ -z "$OPT_SOURCES" ]; then
    324         OPT_SOURCES=true
    325         log "Auto-config: --sources  (remote Darwin build)."
    326     fi
    327     SYSTEMS="$SYSTEMS darwin"
    328 fi
    329 
    330 if [ "$OPT_COPY_PREBUILTS" ]; then
    331     if [ -z "$DARWIN_SSH" ]; then
    332         panic "The --copy-prebuilts=<dir> option requires --darwin-ssh=<host>."
    333     fi
    334     TARGET_AOSP=$OPT_COPY_PREBUILTS
    335     if [ ! -f "$TARGET_AOSP/build/envsetup.sh" ]; then
    336         panic "Not an AOSP checkout / workspace: $TARGET_AOSP"
    337     fi
    338     TARGET_PREBUILTS_DIR=$TARGET_AOSP/prebuilts/android-emulator
    339     mkdir -p "$TARGET_PREBUILTS_DIR"
    340 fi
    341 
    342 case $VERBOSE in
    343   0|1)
    344     REBUILD_FLAGS=""
    345     ;;
    346   2)
    347     REBUILD_FLAGS="--verbose"
    348     ;;
    349   *)
    350     REBUILD_FLAGS="--verbose --verbose"
    351     ;;
    352 esac
    353 
    354 # Remove duplicates.
    355 SYSTEMS=$(echo "$SYSTEMS" | tr ' ' '\n' | sort -u | tr '\n' ' ')
    356 log "Building for the following systems: $SYSTEMS"
    357 
    358 # Default build directory.
    359 TEMP_BUILD_DIR=/tmp/$USER-qemu-package-binaries
    360 
    361 # Ensure the build directory is removed when the script exits or is
    362 # interrupted.
    363 clean_exit () {
    364     if [ -n "$TEMP_BUILD_DIR" -a -d "$TEMP_BUILD_DIR" ]; then
    365         rm -rf "$TEMP_BUILD_DIR"
    366     fi
    367     exit $?
    368 }
    369 
    370 trap "clean_exit 0" EXIT
    371 trap "clean_exit \$?" QUIT HUP INT
    372 
    373 # Do some sanity checks to verify that the current source directory
    374 # doesn't have unchecked files and other bad things lingering.
    375 
    376 # Assume this script is under distrib/
    377 QEMU_DIR=$(cd "$PROGDIR"/.. && pwd -P)
    378 log "Found emulator directory: $QEMU_DIR"
    379 
    380 cd $QEMU_DIR
    381 if [ ! -d "$QEMU_DIR"/.git ]; then
    382     panic "This directory must be a checkout of \$AOSP/platform/external/qemu!"
    383 fi
    384 UNCHECKED_FILES=$(git ls-files -o -x objs/ -x images/emulator_icon.o)
    385 if [ "$UNCHECKED_FILES" ]; then
    386     echo "ERROR: There are unchecked files in the current directory!"
    387     echo "Please remove them:"
    388     echo "$UNCHECKED_FILES"
    389     exit 1
    390 fi
    391 
    392 extract_git_commit_description QEMU_GIT_COMMIT "$QEMU_DIR"
    393 GTEST_DIR=$(dirname $QEMU_DIR)/gtest
    394 if [ ! -d "$GTEST_DIR" ]; then
    395   panic "Cannot find GoogleTest source directory: $GTEST_DIR"
    396 fi
    397 log "Found GoogleTest directory: $GTEST_DIR"
    398 extract_git_commit_description GTEST_GIT_COMMIT "$GTEST_DIR"
    399 
    400 EMUGL_DIR=$QEMU_DIR/../../sdk/emulator/opengl
    401 if [ ! -d "$EMUGL_DIR" ]; then
    402   panic "Cannot find GPU emulation source directory: $EMUGL_DIR"
    403 fi
    404 log "Found GPU emulation directory: $EMUGL_DIR"
    405 extract_git_commit_description EMUGL_GIT_COMMIT "$EMUGL_DIR"
    406 
    407 SOURCES_PKG_FILE=
    408 if [ "$OPT_SOURCES" ]; then
    409     BUILD_DIR=$TEMP_BUILD_DIR/sources/$PKG_PREFIX-$PKG_REVISION
    410     PKG_NAME="$PKG_REVISION-sources"
    411     dump "[$PKG_NAME] Copying GoogleTest source files."
    412     copy_directory_git_files "$GTEST_DIR" "$BUILD_DIR"/gtest
    413 
    414     dump "[$PKG_NAME] Copying Emulator source files."
    415     copy_directory_git_files "$QEMU_DIR" "$BUILD_DIR"/qemu
    416 
    417     dump "[$PKG_NAME] Copying GPU emulation library sources."
    418     copy_directory_git_files "$EMUGL_DIR" "$BUILD_DIR"/opengl
    419 
    420     dump "[$PKG_NAME] Generating README file."
    421     cat > "$BUILD_DIR"/README <<EOF
    422 This directory contains the sources of the Android emulator.
    423 Use './rebuild.sh' to rebuild the binaries from scratch.
    424 EOF
    425 
    426     dump "[$PKG_NAME] Generating rebuild script."
    427     cat > "$BUILD_DIR"/rebuild.sh <<EOF
    428 #!/bin/sh
    429 
    430 # Auto-generated script used to rebuild the Android emulator binaries
    431 # from sources. Note that this does not include the GLES emulation
    432 # libraries.
    433 
    434 cd \$(dirname "\$0") &&
    435 (cd qemu && ./android-rebuild.sh --ignore-audio) &&
    436 mkdir -p bin/ &&
    437 cp -rfp qemu/objs/emulator* bin/ &&
    438 echo "Emulator binaries are under \$(pwd -P)/bin/"
    439 echo "IMPORTANT: The GLES emulation libraries must be copied to:"
    440 echo "    \$(pwd -P)/bin/lib"
    441 EOF
    442 
    443     chmod +x "$BUILD_DIR"/rebuild.sh
    444 
    445     PKG_FILE=$PKG_DIR/$PKG_PREFIX-$PKG_REVISION-sources.tar.bz2
    446     SOURCES_PKG_FILE=$PKG_FILE
    447     dump "[$PKG_NAME] Creating tarball..."
    448     (run cd "$BUILD_DIR"/.. && run tar cjf "$PKG_FILE" $PKG_PREFIX-$PKG_REVISION)
    449 fi
    450 
    451 for SYSTEM in $SYSTEMS; do
    452     PKG_NAME="$PKG_REVISION-$SYSTEM"
    453     dump "[$PKG_NAME] Rebuilding binaries from sources."
    454     run cd $QEMU_DIR
    455     case $SYSTEM in
    456         $HOST_SYSTEM)
    457             run ./android-rebuild.sh $REBUILD_FLAGS || panic "Use ./android-rebuild.sh to see why."
    458             ;;
    459         darwin)
    460             if [ -z "$DARWIN_SSH" ]; then
    461                 # You can only rebuild Darwin binaries on non-Darwin systems
    462                 # by using --darwin-ssh=<host>.
    463                 panic "You can only rebuild Darwin binaries with --darwin-ssh"
    464             fi
    465             if [ -z "$SOURCES_PKG_FILE" ]; then
    466                 panic "You must use --sources to build Darwin binaries through ssh"
    467             fi
    468             build_darwin_binaries_on "$DARWIN_SSH" "$SOURCES_PKG_FILE"
    469             ;;
    470         windows)
    471             if [ "$HOST_SYSTEM" != "linux" ]; then
    472                 panic "Windows binaries can only be rebuilt on Linux!"
    473             fi
    474             run ./android-rebuild.sh --mingw $REBUILD_FLAGS || panic "Use ./android-rebuild.sh --mingw to see why."
    475             ;;
    476         *)
    477             panic "Can't rebuild $SYSTEM binaries on $HOST_SYSTEM for now!"
    478             ;;
    479     esac
    480 
    481     dump "[$PKG_NAME] Copying emulator binaries."
    482     TEMP_PKG_DIR=$TEMP_BUILD_DIR/$SYSTEM/$PKG_PREFIX-$PKG_REVISION
    483     run mkdir -p "$TEMP_PKG_DIR"/tools
    484 
    485     run cp -p objs/emulator* "$TEMP_PKG_DIR"/tools
    486     if [ -d "objs/lib" ]; then
    487         dump "[$PKG_NAME] Copying GLES emulation libraries."
    488         run mkdir -p "$TEMP_PKG_DIR"/tools/lib
    489         run2 cp -rp objs/lib/* "$TEMP_PKG_DIR"/tools/lib/
    490     fi
    491 
    492     dump "[$PKG_NAME] Creating README file."
    493     cat > $TEMP_PKG_DIR/README <<EOF
    494 This directory contains Android emulator binaries. You can use them directly
    495 by defining ANDROID_SDK_ROOT in your environment, then call tools/emulator
    496 with the usual set of options.
    497 
    498 To install them directly into your SDK, copy them with:
    499 
    500     cp -r tools/* \$ANDROID_SDK_ROOT/tools/
    501 EOF
    502 
    503     dump "[$PKG_NAME] Copying license files."
    504     mkdir -p "$TEMP_PKG_DIR"/licenses/
    505     cp COPYING COPYING.LIB "$TEMP_PKG_DIR"/licenses/
    506 
    507     dump "[$PKG_NAME] Creating tarball."
    508     PKG_FILE=$PKG_DIR/$PKG_PREFIX-$PKG_REVISION-$SYSTEM.tar.bz2
    509     (run cd "$TEMP_BUILD_DIR"/$SYSTEM && run tar cjf $PKG_FILE $PKG_PREFIX-$PKG_REVISION)
    510 done
    511 
    512 if [ "$OPT_COPY_PREBUILTS" ]; then
    513     for SYSTEM in linux darwin; do
    514         SRC_DIR="$TEMP_BUILD_DIR"/$SYSTEM/$PKG_PREFIX-$PKG_REVISION
    515         DST_DIR=$TARGET_PREBUILTS_DIR/$SYSTEM-x86_64
    516         dump "[$SYSTEM-x86_64] Copying emulator binaries into $DST_DIR"
    517         run mkdir -p "$DST_DIR" || panic "Could not create directory: $DST_DIR"
    518         case $SYSTEM in
    519             linux) DLLEXT=.so;;
    520             darwin) DLLEXT=.dylib;;
    521             *) panic "Unsupported prebuilt system: $SYSTEM";;
    522         esac
    523         FILES="emulator"
    524         for ARCH in arm x86 mips; do
    525             FILES="$FILES emulator64-$ARCH"
    526         done
    527         for LIB in OpenglRender EGL_translator GLES_CM_translator GLES_V2_translator; do
    528             FILES="$FILES lib/lib64$LIB$DLLEXT"
    529         done
    530         (run cd "$SRC_DIR/tools" && tar cf - $FILES) | (cd $DST_DIR && tar xf -) ||
    531                 panic "Could not copy binaries to $DST_DIR"
    532     done
    533     cat > $TARGET_PREBUILTS_DIR/README <<EOF
    534 This directory contains prebuilt emulator binaries that were generated by
    535 running the following command on a 64-bit Linux machine:
    536 
    537   external/qemu/distrib/package-release.sh \\
    538       --darwin-ssh=<host> \\
    539       --copy-prebuilts=<path>
    540 
    541 Where <host> is the host name of a Darwin machine, and <path> is the root
    542 path of this AOSP repo workspace.
    543 
    544 Below is the list of specific commits for each input directory used:
    545 
    546 external/gtest       $GTEST_GIT_COMMIT
    547 external/qemu        $QEMU_GIT_COMMIT
    548 sdk/emulator/opengl  $EMUGL_GIT_COMMIT
    549 
    550 EOF
    551 fi
    552 
    553 dump "Done. See $PKG_DIR"
    554 ls -lh "$PKG_DIR"/$PKG_PREFIX-$PKG_REVISION*
    555