#!/bin/sh
#
# Copyright (C) 2010 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.
#

. `dirname $0`/prebuilt-common.sh
PROGDIR=`dirname $0`
PROGNAME=`basename $0`

# This sets HOST_TAG to linux-x86 or darwin-x86 on 64-bit systems
force_32bit_binaries

PLATFORM=
register_option "--platform=<name>" do_platform "Specify API level [autodetect]"
do_platform () { PLATFORM=$1; }

ARCH=
register_option "--arch=<name>" do_arch "Specify architecture name [autodetect]"
do_arch () { ARCH=$1; }

OUT_DIR=/tmp/ndk-$USER/platforms-import
register_var_option "--out-dir=<path>" OUT_DIR "Specify output directory"

TOOLCHAIN_PREFIX=

PROGRAM_PARAMETERS="<build-path>"
PROGRAM_DESCRIPTION=\
"This script is used to import the NDK-exposed system libraries and headers from
an existing platform build, and copy them to a temporary directory that will later
be processed by another script (dev-platform-pack.sh) to archive them properly into
the NDK directory structure (e.g. under development/ndk/platforms/).

By default, the files will be copied to $OUT_DIR, but you can
override this with the --out-dir=<path> option.

The script also extracts the list of dynamic symbols exported by system libraries,
filtering those that should not be exposed through the NDK. You can disable this
with the --no-symbol-filtering option.

The <build-path> parameter must point to the platform build output directory
of a valid Android reference platform build. This is the value of the
\$ANDROID_PRODUCT_OUT variable when doing a build configured with the 'lunch'
utility. It usually looks like <top>/out/target/product/<name> where <top> is
the top-level Android source tree, and <name> is the build product name
(e.g. 'generic' or 'generic_x86' for emulator-specific builds).

The API level is auto-detected from the content of <build-path>, but you
can override it with --platform=<number>.

This script is really in charge of the following tasks:
  
  1/ Detect the platform build's API level by parsing the build.prop
     file. This can overriden with --platform=<number>

  2/ Detect the platform build's target CPU architecture by parsing
     the build.prop file. This can be overriden with --arch=<name>

  3/ Copy system headers from \$ANDROID/framework/base/ and other
     locations into \$OUT_DIR/android-\$API/include or
     \$OUT_DIR/android-\$API/arch-\$ARCH/include

  4/ Locate system shared libraries from \$ANDROID_PRODUCT_OUT/system/lib
     and generate symbol files in \$OUT_DIR/android-\$API/arch-\$ARCH/symbols.

  5/ Copy a few system static libraries (libc.a, libm.a, etc...) used
     to generate static executables. As well as a few key object files
     required by the C runtime (e.g. crtbegin_dynamic.o), when needed.

"


extract_parameters "$@"

if [ -z "$PARAMETERS" ] ; then
    if [ -z "$ANDROID_PRODUCT_OUT" ]; then
        dump "ERROR: Missing path parameter to platform build, see --help for details"
        exit 1
    fi
    # ANDROID_PRODUCT_OUT is defined, so use it
    log "Auto-config: using build path: $ANDROID_PRODUCT_OUT"
else
    ANDROID_PRODUCT_OUT=$PARAMETERS
fi

# Sanity checks for the Android build path
if [ ! -d "$ANDROID_PRODUCT_OUT" ]; then
    dump "ERROR: Not a directory: $ANDROID_PRODUCT_OUT"
    dump "Please point to a valid and complete Android build directory"
    exit 1
fi

BUILD_PROP=$ANDROID_PRODUCT_OUT/system/build.prop
if [ ! -f "$BUILD_PROP" ]; then
    dump "ERROR: Missing file: $BUILD_PROP"
    dump "Please point to a valid and complete Android build directory"
    exit 1
fi
log "Extracting build properties from: $BUILD_PROP"

# Try to get the architecture from build.prop if needed
if [ -z "$ARCH" ]; then
    CPU_ABI=$(awk -F '=' '$1 == "ro.product.cpu.abi"  { print $2; }' $BUILD_PROP)
    if [ $? != 0 ]; then
        dump "ERROR: Could not extract CPU ABI from $BUILD_PROP"
        dump "Please use --arch=<name> to override this. See --help"
        exit 1
    fi
    log "Found target CPU ABI: $CPU_ABI"
    ARCH=$(convert_abi_to_arch $CPU_ABI)
    if [ -z "$ARCH" ]; then
        dump "ERROR: Can't translate $CPU_ABI ABI into CPU architecture!"
        exit 1
    fi
    log "Auto-config: --arch=$ARCH"
fi

# Try to get the API level from build.prop if needed
if [ -z "$PLATFORM" ]; then
    PLATFORM=$(awk -F '=' '$1 == "ro.build.version.sdk" { print $2; }' $BUILD_PROP)
    if [ $? != 0 ] ; then
        dump "WARNING: Could not extract default platform level from $BUILD_PROP!"
        dump "Please use --platform=<name> to override this. See --help"
        exit 1
    fi
    if [ -z "$PLATFORM" ]; then
        dump "ERROR: Couldn't extract API level from: $BUILD_PROP"
        exit 1
    fi
    log "Auto-config: --platform=$PLATFORM"
fi

# Normalize platform name, i.e.
#  3         -> 3
#  android-3 -> 3
#
PLATFORM=${PLATFORM##android-}

PLATFORM_ROOT=$OUT_DIR/android-$PLATFORM/arch-$ARCH
log "Using platform destination path: $PLATFORM_ROOT"

# Return the list of files under a given directory
# $1: directory
# $2: (optional) file patterns
list_regular_files_in ()
{
    local DIR="$1"
    shift
    local PATTERNS="$@"
    if [ -z "$PATTERNS" ]; then
        PATTERNS="."
    fi
    cd "$DIR" && find $PATTERNS -type f | sed -e 's!^./!!g'
}

# Check that a given platform level was listed on the command line
# $1: Platform numerical level (e.g. '3')
# returns true if the platform is listed
platform_check ()
{
    [ "$PLATFORM" -ge "$1" ]
}

# Determine Android build tree root
ANDROID_ROOT=`cd $ANDROID_PRODUCT_OUT/../../../.. && pwd`
log "Android build tree root: $ANDROID_ROOT"
log "Android product out: $ANDROID_PRODUCT_OUT"

if [ -z "$TOOLCHAIN_PREFIX" ]; then
    TOOLCHAIN_NAME=$(get_default_toolchain_name_for_arch $ARCH)
    TOOLCHAIN_PREFIX=$(get_default_toolchain_prefix_for_arch $ARCH)
    TOOLCHAIN_PREFIX=$(get_toolchain_install $ANDROID_NDK_ROOT $TOOLCHAIN_NAME)/bin/$TOOLCHAIN_PREFIX
    TOOLCHAIN_PREFIX=${TOOLCHAIN_PREFIX%%-}
    if [ -z "$TOOLCHAIN_PREFIX" ]; then
        echo "ERROR: Unsupported architecture"
        exit 1
    fi
    log "Auto-config: --toolchain-prefix=$TOOLCHAIN_PREFIX"
fi

if [ ! -d "$(dirname $TOOLCHAIN_PREFIX)" ]; then
    echo "ERROR: Toolchain not installed, missing directory: $(dirname $TOOLCHAIN_PREFIX)"
    exit 1
fi

if [ ! -f "$TOOLCHAIN_PREFIX-readelf" ]; then
    echo "ERROR: Toolchain not installed, missing program: $TOOLCHAIN_PREFIX-readelf"
    exit 1
fi


# 'Copy' a given system library. This really reads the shared library to
# to generate a small shell version that will be installed at the destination
# $1: Library name (e.g. libEGL.so)
#
copy_system_shared_library ()
{
    local src="$ANDROID_PRODUCT_OUT/system/lib/$1.so"
    if [ ! -f "$src" ] ; then
        dump "ERROR: Missing system library: $src"
        exit 1
    fi
    local dst="$PLATFORM_ROOT/lib/$1.so"
    mkdir -p `dirname "$dst"` && cp "$src" "$dst"
}

copy_system_static_library ()
{
    local src="$ANDROID_PRODUCT_OUT/obj/STATIC_LIBRARIES/$1_intermediates/$1.a"
    if [ ! -f "$src" ] ; then
        dump "ERROR: Missing system static library: $src"
        exit 1
    fi
    local dst="$PLATFORM_ROOT/lib/$1.a"
    log "Copying system static library: $1.a"
    mkdir -p `dirname "$dst"` && cp -f "$src" "$dst"
}

copy_system_object_file ()
{
    local src="$ANDROID_PRODUCT_OUT/obj/lib/$1.o"
    if [ ! -f "$src" ] ; then
        dump "ERROR: Missing system object file: $src"
        exit 1
    fi
    local dst="$PLATFORM_ROOT/lib/$1.o"
    log "Copying system object file: $1.o"
    mkdir -p `dirname "$dst"` &&
    cp -f "$src" "$dst"
}

# Copy the content of a given directory to $SYSROOT/usr/include
# $1: Source directory
# $2+: List of headers
copy_system_headers ()
{
    local srcdir="$1"
    shift
    local header
    log "Copying system headers from: $srcdir"
    for header; do
        log "  $header"
        local src="$srcdir/$header"
        local dst="$PLATFORM_ROOT/../include/$header"
        if [ ! -f "$srcdir/$header" ] ; then
            dump "ERROR: Missing system header: $srcdir/$header"
            exit 1
        fi
        mkdir -p `dirname "$dst"` && cp -f "$src" "$dst"
        if [ $? != 0 ] ; then
            dump "ERROR: Could not copy system header: $src"
            dump "Target location: $dst"
            exit 1
        fi
    done
}

# Copy all headers found under $1
# $1: source directory
copy_system_headers_from ()
{
    local headers=$(list_regular_files_in "$1")
    copy_system_headers $1 $headers
}

# Same as copy_system_headers, but for arch-specific files
# $1: Source directory
# $2+: List of headers
copy_arch_system_headers ()
{
    local srcdir="$1"
    shift
    local header
    for header; do
        log "Copying $arch system header: $header"
        local src="$srcdir/$header"
        local dst="$PLATFORM_ROOT/include/$header"
        if [ ! -f "$srcdir/$header" ] ; then
            dump "ERROR: Missing $ARCH system header: $srcdir/$header"
            exit 1
        fi
        mkdir -p `dirname "$dst"` && cp -f "$src" "$dst"
        if [ $? != 0 ] ; then
            dump "ERROR: Could not copy $ARCH system header: $src"
            dump "Target location: $dst"
            exit 1
        fi
    done
}

copy_arch_system_headers_from ()
{
    local headers=$(list_regular_files_in "$1")
    copy_arch_system_headers $1 $headers
}

copy_arch_kernel_headers_from ()
{
    local headers=$(list_regular_files_in "$1" asm)
    copy_arch_system_headers $1 $headers
}

# Probe for the location of the OpenSLES sources in the
# platform tree. This used to be system/media/opensles but
# was moved to system/media/wilhelm in Android 4.0
OPENSLES_SUBDIR=system/media/wilhelm
if [ ! -d "$ANDROID_ROOT/$OPENSLES_SUBDIR" ]; then
    OPENSLES_SUBDIR=system/media/opensles
fi

# Now do the work

# API level 3
if platform_check 3; then
    copy_system_shared_library libc
    copy_system_static_library libc
    copy_system_headers_from $ANDROID_ROOT/bionic/libc/include
    copy_arch_system_headers_from $ANDROID_ROOT/bionic/libc/arch-$ARCH/include
    copy_arch_kernel_headers_from $ANDROID_ROOT/bionic/libc/kernel/arch-$ARCH

    copy_system_object_file crtbegin_dynamic
    copy_system_object_file crtbegin_static
    copy_system_object_file crtend_android
    case $ARCH in
    x86)
        copy_system_object_file crtbegin_so
        copy_system_object_file crtend_so
        ;;
    esac

    copy_system_shared_library libm
    copy_system_static_library libm
    copy_system_headers $ANDROID_ROOT/bionic/libm/include math.h
    case "$ARCH" in
    x86 )
        copy_arch_system_headers $ANDROID_ROOT/bionic/libm/include/i387 fenv.h
        ;;
    * )
        copy_arch_system_headers $ANDROID_ROOT/bionic/libm/$ARCH fenv.h
        ;;
    esac

    # The <dlfcn.h> header was already copied from bionic/libc/include
    copy_system_shared_library libdl
    # There is no libdl.a at the moment, we might need one in
    # the future to build gdb-7.1.x though.

    copy_system_shared_library libz
    copy_system_static_library libz
    copy_system_headers $ANDROID_ROOT/external/zlib zconf.h zlib.h

    copy_system_shared_library liblog
    copy_system_headers $ANDROID_ROOT/system/core/include android/log.h

    # NOTE: We do not copy the C++ headers, they are part of the NDK
    #        under $NDK/source/cxx-stl. They were separated from the rest
    #        of the platform headers in order to make room for other STL
    #        implementations (e.g. STLport or GNU Libstdc++-v3)
    #
    copy_system_shared_library libstdc++
    copy_system_static_library libstdc++

    copy_system_headers $ANDROID_ROOT/libnativehelper/include/nativehelper jni.h
fi

# API level 4
if platform_check 4; then
    copy_system_shared_library libGLESv1_CM
    copy_system_headers $ANDROID_ROOT/frameworks/base/opengl/include \
        GLES/gl.h \
        GLES/glext.h \
        GLES/glplatform.h

    copy_system_headers $ANDROID_ROOT/frameworks/base/opengl/include \
        KHR/khrplatform.h
fi

# API level 5
if platform_check 5; then
    copy_system_shared_library libGLESv2
    copy_system_headers $ANDROID_ROOT/frameworks/base/opengl/include \
        GLES2/gl2.h \
        GLES2/gl2ext.h \
        GLES2/gl2platform.h
fi

# API level 8
if platform_check 8; then
    copy_system_shared_library libandroid
    copy_system_shared_library libjnigraphics
    copy_system_headers $ANDROID_ROOT/frameworks/base/native/include \
        android/bitmap.h
fi

# API level 9
if platform_check 9; then
    case $ARCH in
    arm)
        copy_system_object_file crtbegin_so
        copy_system_object_file crtend_so
        ;;
    esac

    copy_system_shared_library libandroid
    copy_system_headers $ANDROID_ROOT/frameworks/base/native/include \
        android/asset_manager.h \
        android/asset_manager_jni.h \
        android/configuration.h \
        android/input.h \
        android/keycodes.h \
        android/looper.h \
        android/native_activity.h \
        android/native_window.h \
        android/native_window_jni.h \
        android/obb.h \
        android/rect.h \
        android/sensor.h \
        android/storage_manager.h \
        android/window.h

    copy_system_shared_library libEGL
    copy_system_headers $ANDROID_ROOT/frameworks/base/opengl/include \
        EGL/egl.h \
        EGL/eglext.h \
        EGL/eglplatform.h

    copy_system_shared_library libOpenSLES
    copy_system_headers $ANDROID_ROOT/$OPENSLES_SUBDIR/include \
        SLES/OpenSLES.h \
        SLES/OpenSLES_Android.h \
        SLES/OpenSLES_AndroidConfiguration.h \
        SLES/OpenSLES_Platform.h
fi

# API level 14
if platform_check 14; then
    copy_system_shared_library libOpenMAXAL
    copy_system_headers $ANDROID_ROOT/system/media/wilhelm/include \
	OMXAL/OpenMAXAL.h \
        OMXAL/OpenMAXAL_Android.h \
        OMXAL/OpenMAXAL_Platform.h

    # This header is new in API level 14
    copy_system_headers $ANDROID_ROOT/$OPENSLES_SUBDIR/include \
        SLES/OpenSLES_AndroidMetadata.h
fi

# Now extract dynamic symbols from the copied shared libraries
# Note that this script will also filter unwanted symbols
log "Generating symbol files"
$PROGDIR/gen-system-symbols.sh "$PLATFORM_ROOT/lib" "$PLATFORM_ROOT/symbols"

# Remove copied shared libraries, we don't need them anymore
# They will be replaced by auto-generated shells by gen-platforms.sh
#
log "Cleaning: $PLATFORM_ROOT/lib/lib*.so"
rm -f "$PLATFORM_ROOT"/lib/lib*.so

log "Done!"