aboutsummaryrefslogtreecommitdiffstats
path: root/scripts/tools/ndk-common.sh
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/tools/ndk-common.sh')
-rw-r--r--scripts/tools/ndk-common.sh1048
1 files changed, 1048 insertions, 0 deletions
diff --git a/scripts/tools/ndk-common.sh b/scripts/tools/ndk-common.sh
new file mode 100644
index 00000000..f6b447cf
--- /dev/null
+++ b/scripts/tools/ndk-common.sh
@@ -0,0 +1,1048 @@
+# Copyright (C) 2009, 2014, 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# A collection of shell function definitions used by various build scripts
+# in the Android NDK (Native Development Kit)
+#
+
+# Get current script name into PROGNAME
+PROGNAME=`basename $0`
+
+# Set package cache directory
+NDK_CACHE_DIR="/var/tmp/ndk-cache-$USER"
+if [ ! -d "$NDK_CACHE_DIR" ]; then
+ mkdir -p "$NDK_CACHE_DIR"
+ if [ $? != 0 ]; then
+ echo "Failed to create cache dir $NDK_CACHE_DIR"
+ exit 1
+ fi
+fi
+
+export TMPDIR=/tmp/ndk-$USER
+
+OS=`uname -s`
+if [ "$OS" == "Darwin" -a -z "$MACOSX_DEPLOYMENT_TARGET" ]; then
+ export MACOSX_DEPLOYMENT_TARGET="10.8"
+fi
+
+# Find the Android NDK root, assuming we are invoked from a script
+# within its directory structure.
+#
+# $1: Variable name that will receive the path
+# $2: Path of invoking script
+find_ndk_root ()
+{
+ # Try to auto-detect the NDK root by walking up the directory
+ # path to the current script.
+ local PROGDIR="`dirname \"$2\"`"
+ while [ -n "1" ] ; do
+ if [ -d "$PROGDIR/build/core" ] ; then
+ break
+ fi
+ if [ -z "$PROGDIR" -o "$PROGDIR" = '/' ] ; then
+ return 1
+ fi
+ PROGDIR="`cd \"$PROGDIR/..\" && pwd`"
+ done
+ eval $1="$PROGDIR"
+}
+
+# Put location of Android NDK into ANDROID_NDK_ROOT and
+# perform a tiny amount of sanity check
+#
+if [ -z "$ANDROID_NDK_ROOT" ] ; then
+ find_ndk_root ANDROID_NDK_ROOT "$0"
+ if [ $? != 0 ]; then
+ echo "Please define ANDROID_NDK_ROOT to point to the root of your"
+ echo "Android NDK installation."
+ exit 1
+ fi
+fi
+
+echo "$ANDROID_NDK_ROOT" | grep -q -e " "
+if [ $? = 0 ] ; then
+ echo "ERROR: The Android NDK installation path contains a space !"
+ echo "Please install to a different location."
+ exit 1
+fi
+
+if [ ! -d $ANDROID_NDK_ROOT ] ; then
+ echo "ERROR: Your ANDROID_NDK_ROOT variable does not point to a directory."
+ exit 1
+fi
+
+if [ ! -f $ANDROID_NDK_ROOT/build/tools/ndk-common.sh ] ; then
+ echo "ERROR: Your ANDROID_NDK_ROOT variable does not point to a valid directory."
+ exit 1
+fi
+
+## Use DRYRUN to find out top-level commands.
+DRYRUN=${DRYRUN-no}
+
+## Logging support
+##
+VERBOSE=${VERBOSE-yes}
+
+
+# If NDK_LOGFILE is defined in the environment, use this as the log file
+TMPLOG=
+if [ -n "$NDK_LOGFILE" ] ; then
+ mkdir -p `dirname "$NDK_LOGFILE"` && touch "$NDK_LOGFILE"
+ TMPLOG="$NDK_LOGFILE"
+fi
+
+# Setup a log file where all log() output will be sent
+#
+# $1: log file path (optional)
+#
+setup_default_log_file ()
+{
+ if [ -n "$NDK_LOGFILE" ] ; then
+ return
+ fi
+ if [ -n "$1" ] ; then
+ NDK_LOGFILE="$1"
+ else
+ NDK_LOGFILE=$TMPDIR/ndk-log-$$.txt
+ fi
+ export NDK_LOGFILE
+ TMPLOG="$NDK_LOGFILE"
+ rm -rf "$TMPLOG" && mkdir -p `dirname "$TMPLOG"` && touch "$TMPLOG"
+ echo "To follow build in another terminal, please use: tail -F $TMPLOG"
+}
+
+dump ()
+{
+ if [ -n "$TMPLOG" ] ; then
+ echo "$@" >> $TMPLOG
+ fi
+ echo "$@"
+}
+
+dump_n ()
+{
+ if [ -n "$TMPLOG" ] ; then
+ printf %s "$@" >> $TMPLOG
+ fi
+ printf %s "$@"
+}
+
+log ()
+{
+ if [ "$VERBOSE" = "yes" ] ; then
+ echo "$@"
+ else
+ if [ -n "$TMPLOG" ] ; then
+ echo "$@" >> $TMPLOG
+ fi
+ fi
+}
+
+log_n ()
+{
+ if [ "$VERBOSE" = "yes" ] ; then
+ printf %s "$@"
+ else
+ if [ -n "$TMPLOG" ] ; then
+ printf %s "$@" >> $TMPLOG
+ fi
+ fi
+}
+
+run ()
+{
+ if [ "$DRYRUN" = "yes" ] ; then
+ echo "## SKIP COMMAND: $@"
+ elif [ "$VERBOSE" = "yes" ] ; then
+ echo "## COMMAND: $@"
+ "$@" 2>&1
+ else
+ if [ -n "$TMPLOG" ] ; then
+ echo "## COMMAND: $@" >> $TMPLOG
+ "$@" >>$TMPLOG 2>&1
+ else
+ "$@" > /dev/null 2>&1
+ fi
+ fi
+}
+
+panic ()
+{
+ dump "ERROR: $@"
+ exit 1
+}
+
+fail_panic ()
+{
+ if [ $? != 0 ] ; then
+ dump "ERROR: $@"
+ exit 1
+ fi
+}
+
+fail_warning ()
+{
+ if [ $? != 0 ] ; then
+ dump "WARNING: $@"
+ fi
+}
+
+
+## Utilities
+##
+
+# Return the value of a given named variable
+# $1: variable name
+#
+# example:
+# FOO=BAR
+# BAR=ZOO
+# echo `var_value $FOO`
+# will print 'ZOO'
+#
+var_value ()
+{
+ # find a better way to do that ?
+ eval echo "$`echo $1`"
+}
+
+# convert to uppercase
+# assumes tr is installed on the platform ?
+#
+to_uppercase ()
+{
+ echo $1 | tr "[:lower:]" "[:upper:]"
+}
+
+## First, we need to detect the HOST CPU, because proper HOST_ARCH detection
+## requires platform-specific tricks.
+##
+HOST_EXE=""
+HOST_OS=`uname -s`
+case "$HOST_OS" in
+ Darwin)
+ HOST_OS=darwin
+ ;;
+ Linux)
+ # note that building 32-bit binaries on x86_64 is handled later
+ HOST_OS=linux
+ ;;
+ FreeBsd) # note: this is not tested
+ HOST_OS=freebsd
+ ;;
+ CYGWIN*|*_NT-*)
+ HOST_OS=windows
+ HOST_EXE=.exe
+ if [ "x$OSTYPE" = xcygwin ] ; then
+ HOST_OS=cygwin
+ fi
+ ;;
+esac
+
+#log "HOST_OS=$HOST_OS"
+#log "HOST_EXE=$HOST_EXE"
+
+## Now find the host architecture. This must correspond to the bitness of
+## the binaries we're going to run with this NDK. Certain platforms allow
+## you to use a 64-bit kernel with a 32-bit userland, and unfortunately
+## commands like 'uname -m' only report the kernel bitness.
+##
+HOST_ARCH=`uname -m`
+case "$HOST_ARCH" in
+ i?86) HOST_ARCH=x86
+ # "uname -m" reports i386 on Snow Leopard even though its architecture is
+ # 64-bit. In order to use it to build 64-bit toolchains we need to fix the
+ # reporting anomoly here.
+ if [ "$HOST_OS" = darwin ] ; then
+ if ! echo __LP64__ | (CCOPTS= gcc -E - 2>/dev/null) | grep -q __LP64__ ; then
+ # or if gcc -dM -E - < /dev/null | grep -q __LP64__; then
+ HOST_ARCH=x86_64
+ fi
+ fi
+ ;;
+ amd64) HOST_ARCH=x86_64
+ ;;
+ powerpc) HOST_ARCH=ppc
+ ;;
+esac
+
+HOST_FILE_PROGRAM="file"
+case "$HOST_OS-$HOST_ARCH" in
+ linux-x86_64|darwin-x86_64)
+ ## On Linux or Darwin, a 64-bit kernel doesn't mean that the user-land
+ ## is always 32-bit, so use "file" to determine the bitness of the shell
+ ## that invoked us. The -L option is used to de-reference symlinks.
+ ##
+ ## Note that on Darwin, a single executable can contain both x86 and
+ ## x86_64 machine code, so just look for x86_64 (darwin) or x86-64 (Linux)
+ ## in the output.
+ ##
+ ## Also note that some versions of 'file' in MacPort may report erroneous
+ ## result. See http://b.android.com/53769. Use /usr/bin/file if exists.
+ if [ "$HOST_OS" = "darwin" ]; then
+ SYSTEM_FILE_PROGRAM="/usr/bin/file"
+ test -x "$SYSTEM_FILE_PROGRAM" && HOST_FILE_PROGRAM="$SYSTEM_FILE_PROGRAM"
+ fi
+ "$HOST_FILE_PROGRAM" -L "$SHELL" | grep -q "x86[_-]64"
+ if [ $? != 0 ]; then
+ # $SHELL is not a 64-bit executable, so assume our userland is too.
+ log "Detected 32-bit userland on 64-bit kernel system!"
+ HOST_ARCH=x86
+ fi
+ ;;
+esac
+
+#log "HOST_ARCH=$HOST_ARCH"
+
+# at this point, the supported values for HOST_ARCH are:
+# x86
+# x86_64
+# ppc
+#
+# other values may be possible but haven't been tested
+#
+# at this point, the value of HOST_OS should be one of the following:
+# linux
+# darwin
+# windows (MSys)
+# cygwin
+#
+# Note that cygwin is treated as a special case because it behaves very differently
+# for a few things. Other values may be possible but have not been tested
+#
+
+# define HOST_TAG as a unique tag used to identify both the host OS and CPU
+# supported values are:
+#
+# linux-x86
+# linux-x86_64
+# darwin-x86
+# darwin-x86_64
+# darwin-ppc
+# windows
+# windows-x86_64
+#
+# other values are possible but were not tested.
+#
+compute_host_tag ()
+{
+ HOST_TAG=${HOST_OS}-${HOST_ARCH}
+ # Special case for windows-x86 => windows
+ case $HOST_TAG in
+ windows-x86|cygwin-x86)
+ HOST_TAG="windows"
+ ;;
+ esac
+ #log "HOST_TAG=$HOST_TAG"
+}
+
+compute_host_tag
+
+# Compute the number of host CPU cores an HOST_NUM_CPUS
+#
+case "$HOST_OS" in
+ linux)
+ HOST_NUM_CPUS=`cat /proc/cpuinfo | grep processor | wc -l`
+ ;;
+ darwin|freebsd)
+ HOST_NUM_CPUS=`sysctl -n hw.ncpu`
+ ;;
+ windows|cygwin)
+ HOST_NUM_CPUS=$NUMBER_OF_PROCESSORS
+ if [ -z "$HOST_NUM_CPUS" ]; then
+ # In case we're running shell from Cygwin SSH, we have no $NUMBER_OF_PROCESSORS
+ # In such case detect it in another way
+ HOST_NUM_CPUS=`cmd /c "echo %NUMBER_OF_PROCESSORS%" 2>/dev/null | tr -d '\r'`
+ fi
+ ;;
+ *) # let's play safe here
+ HOST_NUM_CPUS=1
+esac
+
+test -z "$HOST_NUM_CPUS" && HOST_NUM_CPUS=1
+test $HOST_NUM_CPUS -lt 1 && HOST_NUM_CPUS=1
+
+#log "HOST_NUM_CPUS=$HOST_NUM_CPUS"
+
+# If BUILD_NUM_CPUS is not already defined in your environment,
+# define it as the double of HOST_NUM_CPUS. This is used to
+# run Make commands in parralles, as in 'make -j$BUILD_NUM_CPUS'
+#
+if [ -z "$BUILD_NUM_CPUS" ] ; then
+ BUILD_NUM_CPUS=`expr $HOST_NUM_CPUS \* 2`
+fi
+
+#log "BUILD_NUM_CPUS=$BUILD_NUM_CPUS"
+
+
+## HOST TOOLCHAIN SUPPORT
+##
+
+# force the generation of 32-bit binaries on 64-bit systems
+#
+FORCE_32BIT=no
+force_32bit_binaries ()
+{
+ if [ "$HOST_ARCH" = x86_64 ] ; then
+ log "Forcing generation of 32-bit host binaries on $HOST_ARCH"
+ FORCE_32BIT=yes
+ HOST_ARCH=x86
+ log "HOST_ARCH=$HOST_ARCH"
+ compute_host_tag
+ fi
+}
+
+# On Windows, cygwin binaries will be generated by default, but
+# you can force mingw ones that do not link to cygwin.dll if you
+# call this function.
+#
+disable_cygwin ()
+{
+ if [ $HOST_OS = cygwin ] ; then
+ log "Disabling cygwin binaries generation"
+ CFLAGS="$CFLAGS -mno-cygwin"
+ LDFLAGS="$LDFLAGS -mno-cygwin"
+ HOST_OS=windows
+ compute_host_tag
+ fi
+}
+
+# Various probes are going to need to run a small C program
+mkdir -p $TMPDIR/tmp/tests
+
+TMPC=$TMPDIR/tmp/tests/test-$$.c
+TMPO=$TMPDIR/tmp/tests/test-$$.o
+TMPE=$TMPDIR/tmp/tests/test-$$$EXE
+TMPL=$TMPDIR/tmp/tests/test-$$.log
+
+# cleanup temporary files
+clean_temp ()
+{
+ rm -f $TMPC $TMPO $TMPL $TMPE
+}
+
+# cleanup temp files then exit with an error
+clean_exit ()
+{
+ clean_temp
+ exit 1
+}
+
+# this function will setup the compiler and linker and check that they work as advertised
+# note that you should call 'force_32bit_binaries' before this one if you want it to
+# generate 32-bit binaries on 64-bit systems (that support it).
+#
+setup_toolchain ()
+{
+ if [ -z "$CC" ] ; then
+ CC=gcc
+ fi
+ if [ -z "$CXX" ] ; then
+ CXX=g++
+ fi
+ if [ -z "$CXXFLAGS" ] ; then
+ CXXFLAGS="$CFLAGS"
+ fi
+ if [ -z "$LD" ] ; then
+ LD="$CC"
+ fi
+
+ log "Using '$CC' as the C compiler"
+
+ # check that we can compile a trivial C program with this compiler
+ mkdir -p $(dirname "$TMPC")
+ cat > $TMPC <<EOF
+int main(void) {}
+EOF
+
+ if [ "$FORCE_32BIT" = yes ] ; then
+ CC="$CC -m32"
+ CXX="$CXX -m32"
+ LD="$LD -m32"
+ compile
+ if [ $? != 0 ] ; then
+ # sometimes, we need to also tell the assembler to generate 32-bit binaries
+ # this is highly dependent on your GCC installation (and no, we can't set
+ # this flag all the time)
+ CFLAGS="$CFLAGS -Wa,--32"
+ compile
+ fi
+ fi
+
+ compile
+ if [ $? != 0 ] ; then
+ echo "your C compiler doesn't seem to work:"
+ cat $TMPL
+ clean_exit
+ fi
+ log "CC : compiler check ok ($CC)"
+
+ # check that we can link the trivial program into an executable
+ link
+ if [ $? != 0 ] ; then
+ OLD_LD="$LD"
+ LD="$CC"
+ compile
+ link
+ if [ $? != 0 ] ; then
+ LD="$OLD_LD"
+ echo "your linker doesn't seem to work:"
+ cat $TMPL
+ clean_exit
+ fi
+ fi
+ log "Using '$LD' as the linker"
+ log "LD : linker check ok ($LD)"
+
+ # check the C++ compiler
+ log "Using '$CXX' as the C++ compiler"
+
+ cat > $TMPC <<EOF
+#include <iostream>
+using namespace std;
+int main()
+{
+ cout << "Hello World!" << endl;
+ return 0;
+}
+EOF
+
+ compile_cpp
+ if [ $? != 0 ] ; then
+ echo "your C++ compiler doesn't seem to work"
+ cat $TMPL
+ clean_exit
+ fi
+
+ log "CXX : C++ compiler check ok ($CXX)"
+
+ # XXX: TODO perform AR checks
+ AR=ar
+ ARFLAGS=
+}
+
+# try to compile the current source file in $TMPC into an object
+# stores the error log into $TMPL
+#
+compile ()
+{
+ log "Object : $CC -o $TMPO -c $CFLAGS $TMPC"
+ $CC -o $TMPO -c $CFLAGS $TMPC 2> $TMPL
+}
+
+compile_cpp ()
+{
+ log "Object : $CXX -o $TMPO -c $CXXFLAGS $TMPC"
+ $CXX -o $TMPO -c $CXXFLAGS $TMPC 2> $TMPL
+}
+
+# try to link the recently built file into an executable. error log in $TMPL
+#
+link()
+{
+ log "Link : $LD -o $TMPE $TMPO $LDFLAGS"
+ $LD -o $TMPE $TMPO $LDFLAGS 2> $TMPL
+}
+
+# run a command
+#
+execute()
+{
+ log "Running: $*"
+ $*
+}
+
+# perform a simple compile / link / run of the source file in $TMPC
+compile_exec_run()
+{
+ log "RunExec : $CC -o $TMPE $CFLAGS $TMPC"
+ compile
+ if [ $? != 0 ] ; then
+ echo "Failure to compile test program"
+ cat $TMPC
+ cat $TMPL
+ clean_exit
+ fi
+ link
+ if [ $? != 0 ] ; then
+ echo "Failure to link test program"
+ cat $TMPC
+ echo "------"
+ cat $TMPL
+ clean_exit
+ fi
+ $TMPE
+}
+
+pattern_match ()
+{
+ echo "$2" | grep -q -E -e "$1"
+}
+
+# Let's check that we have a working md5sum here
+check_md5sum ()
+{
+ A_MD5=`echo "A" | md5sum | cut -d' ' -f1`
+ if [ "$A_MD5" != "bf072e9119077b4e76437a93986787ef" ] ; then
+ echo "Please install md5sum on this machine"
+ exit 2
+ fi
+}
+
+# Find if a given shell program is available.
+# We need to take care of the fact that the 'which <foo>' command
+# may return either an empty string (Linux) or something like
+# "no <foo> in ..." (Darwin). Also, we need to redirect stderr
+# to /dev/null for Cygwin
+#
+# $1: variable name
+# $2: program name
+#
+# Result: set $1 to the full path of the corresponding command
+# or to the empty/undefined string if not available
+#
+find_program ()
+{
+ local PROG RET
+ PROG=`which $2 2>/dev/null`
+ RET=$?
+ if [ $RET != 0 ]; then
+ PROG=
+ fi
+ eval $1=\"$PROG\"
+ return $RET
+}
+
+prepare_download ()
+{
+ find_program CMD_WGET wget
+ find_program CMD_CURL curl
+ find_program CMD_SCRP scp
+}
+
+find_pbzip2 ()
+{
+ if [ -z "$_PBZIP2_initialized" ] ; then
+ find_program PBZIP2 pbzip2
+ _PBZIP2_initialized="yes"
+ fi
+}
+
+# Download a file with either 'curl', 'wget' or 'scp'
+#
+# $1: source URL (e.g. http://foo.com, ssh://blah, /some/path)
+# $2: target file
+download_file ()
+{
+ # Is this HTTP, HTTPS or FTP ?
+ if pattern_match "^(http|https|ftp):.*" "$1"; then
+ if [ -n "$CMD_WGET" ] ; then
+ run $CMD_WGET -O $2 $1
+ elif [ -n "$CMD_CURL" ] ; then
+ run $CMD_CURL -o $2 $1
+ else
+ echo "Please install wget or curl on this machine"
+ exit 1
+ fi
+ return
+ fi
+
+ # Is this SSH ?
+ # Accept both ssh://<path> or <machine>:<path>
+ #
+ if pattern_match "^(ssh|[^:]+):.*" "$1"; then
+ if [ -n "$CMD_SCP" ] ; then
+ scp_src=`echo $1 | sed -e s%ssh://%%g`
+ run $CMD_SCP $scp_src $2
+ else
+ echo "Please install scp on this machine"
+ exit 1
+ fi
+ return
+ fi
+
+ # Is this a file copy ?
+ # Accept both file://<path> or /<path>
+ #
+ if pattern_match "^(file://|/).*" "$1"; then
+ cp_src=`echo $1 | sed -e s%^file://%%g`
+ run cp -f $cp_src $2
+ return
+ fi
+}
+
+# Form the relative path between from one abs path to another
+#
+# $1 : start path
+# $2 : end path
+#
+# From:
+# http://stackoverflow.com/questions/2564634/bash-convert-absolute-path-into-relative-path-given-a-current-directory
+relpath ()
+{
+ [ $# -ge 1 ] && [ $# -le 2 ] || return 1
+ current="${2:+"$1"}"
+ target="${2:-"$1"}"
+ [ "$target" != . ] || target=/
+ target="/${target##/}"
+ [ "$current" != . ] || current=/
+ current="${current:="/"}"
+ current="/${current##/}"
+ appendix="${target##/}"
+ relative=''
+ while appendix="${target#"$current"/}"
+ [ "$current" != '/' ] && [ "$appendix" = "$target" ]; do
+ if [ "$current" = "$appendix" ]; then
+ relative="${relative:-.}"
+ echo "${relative#/}"
+ return 0
+ fi
+ current="${current%/*}"
+ relative="$relative${relative:+/}.."
+ done
+ relative="$relative${relative:+${appendix:+/}}${appendix#/}"
+ echo "$relative"
+}
+
+# Unpack a given archive
+#
+# $1: archive file path
+# $2: optional target directory (current one if omitted)
+#
+unpack_archive ()
+{
+ local ARCHIVE="$1"
+ local DIR=${2-.}
+ local RESULT TARFLAGS ZIPFLAGS
+ mkdir -p "$DIR"
+ TARFLAGS="xpf"
+ # todo: zuav: ZIPFLAGS="-qo"
+ ZIPFLAGS="q"
+ case "$ARCHIVE" in
+ *.zip)
+ (cd $DIR && run unzip $ZIPFLAGS "$ARCHIVE")
+ ;;
+ *.tar)
+ run tar $TARFLAGS "$ARCHIVE" -C $DIR
+ ;;
+ *.tar.gz)
+ run tar z$TARFLAGS "$ARCHIVE" -C $DIR
+ ;;
+ *.tar.bz2)
+ find_pbzip2
+ if [ -n "$PBZIP2" ] ; then
+ run tar --use-compress-prog=pbzip2 -$TARFLAGS "$ARCHIVE" -C $DIR
+ else
+ run tar j$TARFLAGS "$ARCHIVE" -C $DIR
+ fi
+ # remove ._* files by MacOSX to preserve resource forks we don't need
+ find $DIR -name "\._*" -exec rm {} \;
+ ;;
+ *.tar.xz)
+ run tar J$TARFLAGS "$ARCHIVE" -C $DIR
+ ;;
+ *)
+ panic "Cannot unpack archive with unknown extension: $ARCHIVE"
+ ;;
+ esac
+}
+
+# Pack a given archive
+#
+# $1: archive file path (including extension)
+# $2: source directory for archive content
+# $3+: list of files (including patterns), all if empty
+pack_archive ()
+{
+ local ARCHIVE="$1"
+ local SRCDIR="$2"
+ local SRCFILES
+ local TARFLAGS ZIPFLAGS
+ shift; shift;
+ if [ -z "$1" ] ; then
+ SRCFILES="*"
+ else
+ SRCFILES="$@"
+ fi
+ if [ "`basename $ARCHIVE`" = "$ARCHIVE" ] ; then
+ ARCHIVE="`pwd`/$ARCHIVE"
+ fi
+ mkdir -p `dirname $ARCHIVE`
+ TARFLAGS="cf"
+ ZIPFLAGS="-9qr"
+ # Ensure symlinks are stored as is in zip files. for toolchains
+ # this can save up to 7 MB in the size of the final archive
+ #ZIPFLAGS="$ZIPFLAGS --symlinks"
+ case "$ARCHIVE" in
+ *.zip)
+ (cd $SRCDIR && run zip $ZIPFLAGS "$ARCHIVE" $SRCFILES)
+ ;;
+ *.tar)
+ (cd $SRCDIR && run tar $TARFLAGS "$ARCHIVE" $SRCFILES)
+ ;;
+ *.tar.gz)
+ (cd $SRCDIR && run tar z$TARFLAGS "$ARCHIVE" $SRCFILES)
+ ;;
+ *.tar.bz2)
+ find_pbzip2
+ if [ -n "$PBZIP2" ] ; then
+ (cd $SRCDIR && run tar --use-compress-prog=pbzip2 -$TARFLAGS "$ARCHIVE" $SRCFILES)
+ else
+ (cd $SRCDIR && run tar j$TARFLAGS "$ARCHIVE" $SRCFILES)
+ fi
+ ;;
+ *.tar.xz)
+ (cd $SRCDIR && run tar J$TARFLAGS "$ARCHIVE" $SRCFILES)
+ ;;
+ *)
+ panic "Unsupported archive format: $ARCHIVE"
+ ;;
+ esac
+}
+
+# Copy a directory, create target location if needed
+#
+# $1: source directory
+# $2: target directory location
+#
+copy_directory ()
+{
+ local SRCDIR="$1"
+ local DSTDIR="$2"
+ if [ ! -d "$SRCDIR" ] ; then
+ panic "Can't copy from non-directory: $SRCDIR"
+ fi
+ log "Copying directory: "
+ log " from $SRCDIR"
+ log " to $DSTDIR"
+ mkdir -p "$DSTDIR" && (cd "$SRCDIR" && 2>/dev/null tar cf - *) | (tar xf - -C "$DSTDIR")
+ fail_panic "Cannot copy to directory: $DSTDIR"
+}
+
+# Move a directory, create target location if needed
+#
+# $1: source directory
+# $2: target directory location
+#
+move_directory ()
+{
+ local SRCDIR="$1"
+ local DSTDIR="$2"
+ if [ ! -d "$SRCDIR" ] ; then
+ panic "Can't move from non-directory: $SRCDIR"
+ fi
+ log "Move directory: "
+ log " from $SRCDIR"
+ log " to $DSTDIR"
+ mkdir -p "$DSTDIR" && (mv "$SRCDIR"/* "$DSTDIR")
+ fail_panic "Cannot move to directory: $DSTDIR"
+}
+
+# This is the same than copy_directory(), but symlinks will be replaced
+# by the file they actually point to instead.
+copy_directory_nolinks ()
+{
+ local SRCDIR="$1"
+ local DSTDIR="$2"
+ if [ ! -d "$SRCDIR" ] ; then
+ panic "Can't copy from non-directory: $SRCDIR"
+ fi
+ log "Copying directory (without symlinks): "
+ log " from $SRCDIR"
+ log " to $DSTDIR"
+ mkdir -p "$DSTDIR" && (cd "$SRCDIR" && tar chf - *) | (tar xf - -C "$DSTDIR")
+ fail_panic "Cannot copy to directory: $DSTDIR"
+}
+
+# Copy certain files from one directory to another one
+# $1: source directory
+# $2: target directory
+# $3+: file list (including patterns)
+copy_file_list ()
+{
+ local SRCDIR="$1"
+ local DSTDIR="$2"
+ shift; shift;
+ if [ ! -d "$SRCDIR" ] ; then
+ panic "Cant' copy from non-directory: $SRCDIR"
+ fi
+ # todo zuav: check for number of arguments?
+ #log "Copying file: $@"
+ log "Copying file: $1 $2 $3 ..."
+ log " from $SRCDIR"
+ log " to $DSTDIR"
+
+ mkdir -p "$DSTDIR" && (cd "$SRCDIR" && (echo $@ | tr ' ' '\n' | tar cf - -T -)) | (tar xf - -C "$DSTDIR")
+ fail_panic "Cannot copy files to directory: $DSTDIR"
+}
+
+# Rotate a log file
+# If the given log file exist, add a -1 to the end of the file.
+# If older log files exist, rename them to -<n+1>
+# $1: log file
+# $2: maximum version to retain [optional]
+rotate_log ()
+{
+ # Default Maximum versions to retain
+ local MAXVER="5"
+ local LOGFILE="$1"
+ shift;
+ if [ ! -z "$1" ] ; then
+ local tmpmax="$1"
+ shift;
+ tmpmax=`expr $tmpmax + 0`
+ if [ $tmpmax -lt 1 ] ; then
+ panic "Invalid maximum log file versions '$tmpmax' invalid; defaulting to $MAXVER"
+ else
+ MAXVER=$tmpmax;
+ fi
+ fi
+
+ # Do Nothing if the log file does not exist
+ if [ ! -f "${LOGFILE}" ] ; then
+ return
+ fi
+
+ # Rename existing older versions
+ ver=$MAXVER
+ while [ $ver -ge 1 ]
+ do
+ local prev=$(( $ver - 1 ))
+ local old="-$prev"
+
+ # Instead of old version 0; use the original filename
+ if [ $ver -eq 1 ] ; then
+ old=""
+ fi
+
+ if [ -f "${LOGFILE}${old}" ] ; then
+ mv -f "${LOGFILE}${old}" "${LOGFILE}-${ver}"
+ fi
+
+ ver=$prev
+ done
+}
+
+# Copy a given package to the cache directory
+#
+# $1: package dir
+# $2: archive file name
+cache_package ()
+{
+ local package_dir=$1
+ local archive=$2
+ log "Copying $package_dir/$archive to cache dir $NDK_CACHE_DIR."
+ cp "$package_dir/$archive" "$NDK_CACHE_DIR"
+ fail_panic "Could not cache package: $archive"
+}
+
+# Copy a given cached package if found to the given package directory
+# NB
+# This function will exit a script on succes!
+#
+# $1: package dir
+# $2: archive file name
+# $3: optional, can be anything, prevents exit
+try_cached_package ()
+{
+ local package_dir=$1
+ local archive=$2
+
+ if [ "$package_dir" -a -e "$NDK_CACHE_DIR/$archive" ]; then
+ dump "Found cached package: $NDK_CACHE_DIR/$archive"
+ mkdir -p "$package_dir"
+ cp "$NDK_CACHE_DIR/$archive" "$package_dir"
+ fail_panic "Could not copy $archive from cache directory."
+ if [ -n "$3" ]; then
+ return 0
+ else
+ log "Done"
+ exit 0
+ fi
+ fi
+
+ return 1
+}
+
+# check that every member of the specified list is a member
+# of the second list
+#
+# $1: list of strings separated by blanks
+# $2: list of standard (permitted) values separated by blanks
+# $3: error message, optional
+check_list_values ()
+{
+ #echo "1: $1"
+ #echo "2: $2"
+ #echo "3: $3"
+
+ local list=$1
+ local standard_list=$2
+ local err_msg="bad value"
+
+ if [ -n "$3" ]; then
+ err_msg=$3
+ fi
+
+ local val=
+ local defval=
+ local good=
+ local defsys=
+ for val in $list ; do
+ good=""
+ for defval in $standard_list ; do
+ if [ "$val" = "$defval" ] ; then
+ good="yes"
+ break
+ fi
+ done
+ if [ "$good" != "yes" ] ; then
+ panic "$err_msg: $val"
+ fi
+ done
+}
+
+# Dereference symlink
+# $1+: directories
+dereference_symlink ()
+{
+ local DIRECTORY SYMLINKS DIR FILE LINK
+ for DIRECTORY in "$@"; do
+ if [ -d "$DIRECTORY" ]; then
+ while true; do
+ # Find all symlinks in this directory.
+ SYMLINKS=`find $DIRECTORY -type l`
+ if [ -z "$SYMLINKS" ]; then
+ break;
+ fi
+ # Iterate symlinks
+ for SYMLINK in $SYMLINKS; do
+ if [ -L "$SYMLINK" ]; then
+ DIR=`dirname "$SYMLINK"`
+ FILE=`basename "$SYMLINK"`
+ # Note that if `readlink $FILE` is also a link, we want to deal
+ # with it in the next iteration. There is potential infinite-loop
+ # situation for cicular link doesn't exist in our case, though.
+ (cd "$DIR" && \
+ LINK=`readlink "$FILE"` && \
+ test ! -L "$LINK" && \
+ rm -f "$FILE" && \
+ cp -a "$LINK" "$FILE")
+ fi
+ done
+ done
+ fi
+ done
+}