#!/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` if [ -z "$ANDROID_PRODUCT_OUT" ] ; then echo "ERROR: The environment variable ANDROID_PRODUCT_OUT is not defined!" fi # This sets HOST_TAG to linux-x86 or darwin-x86 on 64-bit systems force_32bit_binaries # We need to extract the auto-detected platform level to display it in # the help. Do not barf if we can't do it right now, to keep --help working # in this case. # BUILD_PROP=$ANDROID_PRODUCT_OUT/system/build.prop if [ ! -f "$BUILD_PROP" ] ; then # Use this as default if the build.prop file does not exist # We will generate an error after the extract_parameters call # in this specific case, but we want --help to work before that. PLATFORM=9 else 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!" PLATFORM=9 dump "Defaulting to $PLATFORM" fi fi PROGRAM_PARAMETERS="<level> [<level2>...]" PROGRAM_DESCRIPTION=\ "This script is used to update the NDK's platform headers and system libraries from those generated after a full build of the Android platform. Run it after modifying and rebuilding one of the public libraries exposed through the NDK. The first parameter must be a platform/API level. For example, to update the NDK definitions for the 'android-9' platform, use one of: $PROGNAME android-9 $PROGNAME 9 You can also use several values to update several levels at once, e.g.: $PROGNAME $API_LEVELS NOTE: The currently auto-detected API level for your build is $PLATFORM, but this value may be incorrect if your platform has not been assigned a new API level yet. This script is really in charge of the following tasks: 1/ Import system headers from \$ANDROID/framework/base/ and other locations in the full system source tree. 2/ Locate system shared libraries from \$ANDROID_PRODUCT_OUT/system/lib and convert them into small "shell" .so files that only export the same functions and variables. These can be used with the NDK at link time, are much smaller, and also do not require the use of special linker flags when used with the standalone NDK toolchain (i.e. -Wl,--allow-shlib-undefined) 3/ For each shared library, also generate a list of symbols exported by the shell. This makes it easier to see with 'git diff' which symbols were added (or even removed) since the last invocation. 4/ 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. By default, all files are placed under \$ANDROID/development/ndk but you can override this with the --out-dir=<path> option. By default, the build-specific platform/API level is autodetected, and only the files under \$ANDROID_ROOT/development/ndk/platforms/android-<level>/ will be affected. This ensures you don't accidentally overwrite files corresponding to previous releases. " ARCH=arm register_var_option "--arch=<name>" ARCH "Specify architecture name." DEVDIR="$ANDROID_NDK_ROOT/../development/ndk" if [ -d "$DEVDIR" ] ; then OUT_DIR=`cd $DEVDIR && pwd` else OUT_DIR= fi register_var_option "--out-dir=<path>" OUT_DIR "Specify output directory." extract_parameters "$@" if [ -z "$PARAMETERS" ] ; then dump "ERROR: Missing required API/platform level. See --help for usage instructions." exit 1 fi # Normalize platform names, i.e. get rid of android- prefix in a list of # platform levels # # 3 android-4 foo-5 -> 3 4 foo-5 (foo-5 is invalid name) # # $1: list of platform levels # normalize_platforms () { echo "$@" | tr ' ' '\n' | sed -e 's!android-!!g' | tr '\n' ' ' } PLATFORMS=`normalize_platforms $PARAMETERS` log "Target platform levels: $PLATFORMS" # 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 () { echo "$PLATFORMS" | tr ' ' '\n' | fgrep -q "$1" if [ $? != 0 ] ; then # Not listed, return an error code for 'if' return 1 else PLATFORM_ROOT="$OUT_DIR/platforms/android-$1/arch-$ARCH" log "Platform root: $PLATFORM_ROOT" return 0 fi } # 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" case $ARCH in arm) TOOLCHAIN=arm-linux-androideabi-4.4.3 PREFIX=arm-linux-androideabi ;; x86) TOOLCHAIN=x86-4.2.1 PREFIX=i686-android-linux-gnu ;; *) echo "ERROR: Unsupported architecture: $ARCH" exit 1 esac TOOLCHAIN_PREFIX=$ANDROID_NDK_ROOT/toolchains/$TOOLCHAIN/prebuilt/$HOST_TAG/bin/$PREFIX log "Toolchain prefix: $TOOLCHAIN_PREFIX" if [ -z "$OUT_DIR" ] ; then dump "ERROR: Could not find valid output directory (e.g. \$NDK/../development/ndk)." dump "Please use --out-dir=<path> to specify one!" exit 1 fi # Check the platform value and set PLATFORM_ROOT # # Normalize the value: android-3 -> android-3 3 -> android-3 PLATFORM=`echo $PLATFORM | sed -e 's!android-!!g'` PLATFORM=android-$PLATFORM # Temp file used to list shared library symbol exclusions # See set_symbol_excludes and extract_shared_library_xxxx functions below SYMBOL_EXCLUDES=/tmp/ndk-symbol-excludes.txt # Temp file used to list shared library symbol inclusions, these # are essentially overrides to the content of SYMBOL_EXCLUDES SYMBOL_INCLUDES=/tmp/ndk-symbol-includes.txt # Reset the symbol exclusion list to its default reset_symbol_excludes () { # By default, do not export C++ mangled symbol, which all start with _Z echo '^_Z' > $SYMBOL_EXCLUDES > $SYMBOL_INCLUDES } # Add new exclusion patterns to SYMBOL_EXCLUDES set_symbol_excludes () { (echo "$@" | tr ' ' '\n') >> $SYMBOL_EXCLUDES } # Add new inclusion patterns to SYMBOL_INCLUDES set_symbol_includes () { (echo "$@" | tr ' ' '\n') >> $SYMBOL_INCLUDES } # Clear symbol exclusion/inclusion files clear_symbol_excludes () { rm -f $SYMBOL_EXCLUDES $SYMBOL_INCLUDES } # Filter the list of symbols from a file # $1: path to symbol list file filter_symbols () { (grep -v -f $SYMBOL_EXCLUDES $1 && grep -f $SYMBOL_INCLUDES $1) | sort -u } # # Dump the list of dynamic functions exported by a given shared library # $1: Path to shared library object extract_shared_library_functions () { $TOOLCHAIN_PREFIX-readelf -s -D -W $1 | awk '$5 ~ /FUNC/ && $6 ~ /GLOBAL/ && $8 !~ /UND/ { print $9; }' > $TMPC filter_symbols $TMPC } # Dump the list of global variables exposed by a given shared library # $1: Path to shared library object extract_shared_library_variables () { $TOOLCHAIN_PREFIX-readelf -s -D -W $1 | awk '$5 ~ /OBJECT/ && $6 ~ /GLOBAL/ && $8 !~ /UND/ { print $9; }' > $TMPC filter_symbols $TMPC } # Generate link library, i.e. a special tiny shell .so that exports the # same symbols as a reference shared library, and can be used during # link with the NDK toolchain. # # Having these shells allows two things: # # - Reduce the size of the NDK release package (some libs are very large) # - Use the standalone toolchain without -Wl,--allow-shlib-undefined # # Note that the list of symbols for each generated library is stored # under arch-$ARCH/symbols/<libname>.txt # # $1: Path to reference shared library # $2: Path to output shared library (can be the same as $1) # generate_shell_library () { # First, extract the list of functions and variables exported by the # reference library. local funcs=`extract_shared_library_functions $1` local vars=`extract_shared_library_variables $1` local numfuncs=`echo $funcs | wc -w` local numvars=`echo $vars | wc -w` dump "Generating shell library for `basename $1` ($numfuncs functions + $numvars variables)" # Now generate a small C source file that contains similarly-named stubs echo "/* Auto-generated file, do not edit */" > $TMPC local func var for func in $funcs; do echo "void $func(void) {}" >> $TMPC done for var in $vars; do echo "int $var;" >> $TMPC done # Build it with our cross-compiler. It will complain about conflicting # types for built-in functions, so just shut it up. $TOOLCHAIN_PREFIX-gcc -Wl,-shared,-Bsymbolic -nostdlib -o $TMPO $TMPC 1>/dev/null 2>&1 if [ $? != 0 ] ; then dump "ERROR: Can't generate shell library for: $1" dump "See the content of $TMPC for details." exit 1 fi # Sanity check: the generated shared library must export the same # functions and variables, or something is really rotten! local newfuncs=`extract_shared_library_functions $TMPO` local newvars=`extract_shared_library_variables $TMPO` if [ "$newfuncs" != "$funcs" ] ; then dump "ERROR: mismatch in generated functions list" exit 1 fi if [ "$newvars" != "$vars" ] ; then dump "ERROR: mismatch in generated variables list" exit 1 fi # Copy to our destination now local libdir=`dirname "$2"` mkdir -p "$libdir" && cp -f $TMPO "$2" if [ $? != 0 ] ; then dump "ERROR: Can't copy shell library for: $1" dump "target location is: $2" exit 1 fi # Write the functions and variables to a symbols file now local symdir=`dirname "$libdir"`/symbols local symfile="$symdir/`basename $1.txt`" dump "Generating symbol file: $symfile" mkdir -p "$symdir" && > $symfile (echo "$funcs" | tr ' ' '\n') >> $symfile (echo "$vars" | tr ' ' '\n') >> $symfile # Clear the export exclusion list reset_symbol_excludes } # '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"` && generate_shell_library "$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" dump "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" dump "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 dump "Copying system headers from: $srcdir" for header; do dump " $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=`cd "$1" && find . -type f | sed -e 's!\./!!g'` 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 dump "Copying $arch system header: $header from $srcdir" 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 } # Now do the work reset_symbol_excludes # API level 3 if platform_check 3; then # Remove a few internal symbols that should not be exposed # from the C library (we plan to clean that up soon by using the # "hidden" visibility attribute in the near future). # set_symbol_excludes \ '^the_' '^dns_' 'load_domain_search_list' 'res_get_dns_changed' \ '^_resolv_cache' '^_dns_getht' '^_thread_atexit' \ '^free_malloc_leak_info' 'fake_gmtime_r' 'fake_localtime_r' \ '^gAllocationsMutex' '^gHashTable' '^gMallocLeakZygoteChild' \ copy_system_shared_library libc copy_system_static_library libc copy_system_headers_from $ANDROID_ROOT/bionic/libc/include copy_system_headers_from $ANDROID_ROOT/bionic/libc/arch-$ARCH/include copy_system_object_file crtbegin_dynamic copy_system_object_file crtbegin_static copy_system_object_file crtend_android copy_system_shared_library libm copy_system_static_library libm copy_system_headers $ANDROID_ROOT/bionic/libm/include math.h copy_arch_system_headers $ANDROID_ROOT/bionic/libm/$ARCH fenv.h # 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 set_symbol_excludes '^.*' # exclude everything set_symbol_includes '^__android_' # except __android_xxxx functions 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++ # We link gdbserver statically with libthreadb, so there is no point # in copying the shared library (which by the way has an unstable ABI # anyway). copy_system_static_library libthread_db copy_system_headers $ANDROID_ROOT/bionic/libthread_db/include thread_db.h copy_system_headers $ANDROID_ROOT/dalvik/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_headers $ANDROID_ROOT/frameworks/base/native/include \ android/bitmap.h fi # API level 9 if platform_check 9; then copy_system_object_file crtbegin_so copy_system_object_file crtend_so 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 set_symbol_excludes '^_' '^MPH_' # remove MPH_to_xxx definitions copy_system_shared_library libOpenSLES copy_system_headers $ANDROID_ROOT/system/media/opensles/include \ SLES/OpenSLES.h \ SLES/OpenSLES_Android.h \ SLES/OpenSLES_AndroidConfiguration.h \ SLES/OpenSLES_Platform.h fi clear_symbol_excludes dump "Done!"