#!/bin/bash # 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. # # Create a standalone toolchain package for Android. . `dirname $0`/prebuilt-common.sh PROGRAM_PARAMETERS="" PROGRAM_DESCRIPTION=\ "Generate a customized Android toolchain installation that includes a working sysroot. The result is something that can more easily be used as a standalone cross-compiler, e.g. to run configure and make scripts." # For now, this is the only toolchain that works reliably. TOOLCHAIN_NAME= register_var_option "--toolchain=" TOOLCHAIN_NAME "Specify toolchain name" USE_LLVM=no do_option_use_llvm () { USE_LLVM=yes } register_option "--use-llvm" do_option_use_llvm "Use LLVM." STL=gnustl register_var_option "--stl=" STL "Specify C++ STL" ARCH= register_var_option "--arch=" ARCH "Specify target architecture" # Grab the ABIs that match the architecture. ABIS= register_var_option "--abis=" ABIS "Specify list of target ABIs." NDK_DIR=`dirname $0` NDK_DIR=`dirname $NDK_DIR` NDK_DIR=`dirname $NDK_DIR` register_var_option "--ndk-dir=" NDK_DIR "Take source files from NDK at " PACKAGE_DIR=$TMPDIR register_var_option "--package-dir=" PACKAGE_DIR "Place package file in " INSTALL_DIR= register_var_option "--install-dir=" INSTALL_DIR "Don't create package, install files to instead." PLATFORM= register_option "--platform=" do_platform "Specify target Android platform/API level." "android-3" do_platform () { PLATFORM=$1; if [ "$PLATFORM" = "android-L" ]; then echo "WARNING: android-L is renamed as android-21" PLATFORM=android-21 fi } extract_parameters "$@" # Check NDK_DIR if [ ! -d "$NDK_DIR/build/core" ] ; then echo "Invalid source NDK directory: $NDK_DIR" echo "Please use --ndk-dir= to specify the path of an installed NDK." exit 1 fi # Check TOOLCHAIN_NAME ARCH_BY_TOOLCHAIN_NAME= if [ -n "$TOOLCHAIN_NAME" ]; then case $TOOLCHAIN_NAME in arm-*) ARCH_BY_TOOLCHAIN_NAME=arm ;; x86-*) ARCH_BY_TOOLCHAIN_NAME=x86 ;; mipsel-*) ARCH_BY_TOOLCHAIN_NAME=mips ;; aarch64-*) ARCH_BY_TOOLCHAIN_NAME=arm64 ;; x86_64-linux-android-*) ARCH_BY_TOOLCHAIN_NAME=x86_64 TOOLCHAIN_NAME=$(echo "$TOOLCHAIN_NAME" | sed -e 's/-linux-android//') echo "Auto-truncate: --toolchain=$TOOLCHAIN_NAME" ;; x86_64-*) ARCH_BY_TOOLCHAIN_NAME=x86_64 ;; mips64el-*) ARCH_BY_TOOLCHAIN_NAME=mips64 ;; *) echo "Invalid toolchain $TOOLCHAIN_NAME" exit 1 ;; esac fi # Check ARCH if [ -z "$ARCH" ]; then ARCH=$ARCH_BY_TOOLCHAIN_NAME if [ -z "$ARCH" ]; then ARCH=arm fi echo "Auto-config: --arch=$ARCH" fi if [ -z "$ABIS" ]; then ABIS=$(convert_arch_to_abi $ARCH) fi if [ -z "$ABIS" ]; then dump "ERROR: No ABIS. Possibly unsupported NDK architecture $ARCH?" exit 1 fi # Check toolchain name if [ -z "$TOOLCHAIN_NAME" ]; then TOOLCHAIN_NAME=$(get_default_toolchain_name_for_arch $ARCH) echo "Auto-config: --toolchain=$TOOLCHAIN_NAME" fi # Detect LLVM version from toolchain name with *clang* TOOLCHAIN_LLVM=$(echo "$TOOLCHAIN_NAME" | grep clang) if [ -n "$TOOLCHAIN_LLVM" ]; then USE_LLVM=yes DEFAULT_GCC_VERSION=$(get_default_gcc_version_for_arch $ARCH) NEW_TOOLCHAIN_NAME=${TOOLCHAIN_NAME%-clang}-${DEFAULT_GCC_VERSION} TOOLCHAIN_NAME=$NEW_TOOLCHAIN_NAME fi # Check PLATFORM if [ -z "$PLATFORM" ] ; then case $ARCH in arm) PLATFORM=android-3 ;; x86|mips) PLATFORM=android-9 ;; arm64|x86_64|mips64) PLATFORM=android-$FIRST_API64_LEVEL ;; *) dump "ERROR: Unsupported NDK architecture $ARCH!" esac echo "Auto-config: --platform=$PLATFORM" fi if [ ! -d "$NDK_DIR/platforms/$PLATFORM" ] ; then echo "Invalid platform name: $PLATFORM" echo "Please use --platform= with one of:" `(cd "$NDK_DIR/platforms" && ls)` exit 1 fi if [ -d "$NDK_DIR/prebuilt/$HOST_TAG" ]; then SYSTEM=$HOST_TAG else SYSTEM=$HOST_TAG32 fi # Check toolchain name TOOLCHAIN_PATH="$NDK_DIR/toolchains/$TOOLCHAIN_NAME/prebuilt/$SYSTEM" if [ ! -d "$TOOLCHAIN_PATH" ] ; then echo "Could not find toolchain: $TOOLCHAIN_PATH" echo "Please use --toolchain= with the name of a toolchain supported by the source NDK." echo "Try one of: " `(cd "$NDK_DIR/toolchains" && ls)` exit 1 fi # Extract architecture from platform name parse_toolchain_name $TOOLCHAIN_NAME case "$TOOLCHAIN_NAME" in *4.9l) GCC_VERSION=4.9l ;; *4.8l) GCC_VERSION=4.8l ;; esac # Check that there are any platform files for it! (cd $NDK_DIR/platforms && ls -d */arch-$ARCH >/dev/null 2>&1 ) if [ $? != 0 ] ; then echo "Platform $PLATFORM doesn't have any files for this architecture: $ARCH" echo "Either use --platform= or --toolchain= to select a different" echo "platform or arch-dependent toolchain name (respectively)!" exit 1 fi # Compute source sysroot SRC_SYSROOT_INC="$NDK_DIR/platforms/$PLATFORM/arch-$ARCH/usr/include" SRC_SYSROOT_LIB="$NDK_DIR/platforms/$PLATFORM/arch-$ARCH/usr/lib" if [ ! -d "$SRC_SYSROOT_INC" -o ! -d "$SRC_SYSROOT_LIB" ] ; then echo "No platform files ($PLATFORM) for this architecture: $ARCH" exit 1 fi # Check that we have any prebuilts GCC toolchain here if [ ! -d "$TOOLCHAIN_PATH" ]; then echo "Toolchain is missing prebuilt files: $TOOLCHAIN_NAME" echo "You must point to a valid NDK release package!" exit 1 fi TOOLCHAIN_PATH="$TOOLCHAIN_PATH" TOOLCHAIN_GCC=$TOOLCHAIN_PATH/bin/$ABI_CONFIGURE_TARGET-gcc if [ ! -f "$TOOLCHAIN_GCC" ] ; then echo "Toolchain $TOOLCHAIN_GCC is missing!" exit 1 fi if [ "$USE_LLVM" = "yes" ]; then LLVM_TOOLCHAIN_PATH="$NDK_DIR/toolchains/llvm/prebuilt/$SYSTEM" # Check that we have any prebuilts LLVM toolchain here if [ ! -d "$LLVM_TOOLCHAIN_PATH" ] ; then echo "LLVM Toolchain is missing prebuilt files" echo "You must point to a valid NDK release package!" exit 1 fi LLVM_TOOLCHAIN_PATH="$LLVM_TOOLCHAIN_PATH" fi # Get GCC_BASE_VERSION. Note that GCC_BASE_VERSION may be slightly different from GCC_VERSION. # eg. In gcc4.9 GCC_BASE_VERSION is "4.9.x-google" LIBGCC_PATH=`$TOOLCHAIN_GCC -print-libgcc-file-name` LIBGCC_BASE_PATH=${LIBGCC_PATH%/*} # base path of libgcc.a GCC_BASE_VERSION=${LIBGCC_BASE_PATH##*/} # stuff after the last / # Create temporary directory TMPDIR=$NDK_TMPDIR/standalone/$TOOLCHAIN_NAME dump "Copying prebuilt binaries..." # Now copy the GCC toolchain prebuilt binaries copy_directory "$TOOLCHAIN_PATH" "$TMPDIR" # Copy python-related to for gdb.exe PYTHON=python PYTHON_x=python$(echo "$DEFAULT_PYTHON_VERSION" | cut -d . -f 1) PYTHON_xdotx=python$(echo "$DEFAULT_PYTHON_VERSION" | cut -d . -f 1-2) copy_directory "$NDK_DIR/prebuilt/$SYSTEM/include/$PYTHON_xdotx" "$TMPDIR/include/$PYTHON_xdotx" copy_directory "$NDK_DIR/prebuilt/$SYSTEM/lib/$PYTHON_xdotx" "$TMPDIR/lib/$PYTHON_xdotx" copy_file_list "$NDK_DIR/prebuilt/$SYSTEM/bin" "$TMPDIR/bin" "$PYTHON$HOST_EXE" "$PYTHON_x$HOST_EXE" "$PYTHON_xdotx$HOST_EXE" if [ "$HOST_TAG32" = "windows" ]; then copy_file_list "$NDK_DIR/prebuilt/$SYSTEM/bin" "$TMPDIR/bin" lib$PYTHON_xdotx.dll fi # Copy yasm for x86 if [ "$ARCH" = "x86" ]; then copy_file_list "$NDK_DIR/prebuilt/$SYSTEM/bin" "$TMPDIR/bin" "yasm$HOST_EXE" fi # Clang stuff if [ "$USE_LLVM" = "yes" ]; then # Copy the clang/llvm toolchain prebuilt binaries copy_directory "$LLVM_TOOLCHAIN_PATH" "$TMPDIR" # Move clang and clang++ to clang${LLVM_VERSION} and clang${LLVM_VERSION}++, # then create scripts linking them with predefined -target flag. This is to # make clang/++ easier drop-in replacement for gcc/++ in NDK standalone mode. # Note that the file name of "clang" isn't important, and the trailing # "++" tells clang to compile in C++ mode LLVM_TARGET= case "$ARCH" in arm) # Note: -target may change by clang based on the presence of # subsequent -march=armv5te and/or -mthumb. LLVM_TARGET=armv7a-none-linux-androideabi TOOLCHAIN_PREFIX=$DEFAULT_ARCH_TOOLCHAIN_PREFIX_arm ;; x86) LLVM_TARGET=i686-none-linux-android TOOLCHAIN_PREFIX=$DEFAULT_ARCH_TOOLCHAIN_PREFIX_x86 ;; mips) LLVM_TARGET=mipsel-none-linux-android TOOLCHAIN_PREFIX=$DEFAULT_ARCH_TOOLCHAIN_PREFIX_mips ;; arm64) LLVM_TARGET=aarch64-none-linux-android TOOLCHAIN_PREFIX=$DEFAULT_ARCH_TOOLCHAIN_PREFIX_arm64 ;; x86_64) LLVM_TARGET=x86_64-none-linux-android TOOLCHAIN_PREFIX=$DEFAULT_ARCH_TOOLCHAIN_PREFIX_x86_64 ;; mips64) LLVM_TARGET=mips64el-none-linux-android TOOLCHAIN_PREFIX=$DEFAULT_ARCH_TOOLCHAIN_PREFIX_mips64 ;; *) dump "ERROR: Unsupported NDK architecture $ARCH!" esac # We need to copy clang and clang++ to some other named binary because clang # and clang++ are going to be the shell scripts with the prefilled target. We # have the version info available, and that's a typical alternate name (and is # what we historically used). LLVM_VERSION=$(cat $LLVM_TOOLCHAIN_PATH/AndroidVersion.txt | \ egrep -o '[[:digit:]]+\.[[:digit:]]') # Need to remove '.' from LLVM_VERSION when constructing new clang name, # otherwise clang3.3++ may still compile *.c code as C, not C++, which # is not consistent with g++ LLVM_VERSION_WITHOUT_DOT=$(echo "$LLVM_VERSION" | sed -e "s!\.!!") mv "$TMPDIR/bin/clang${HOST_EXE}" "$TMPDIR/bin/clang${LLVM_VERSION_WITHOUT_DOT}${HOST_EXE}" if [ -h "$TMPDIR/bin/clang++${HOST_EXE}" ] ; then ## clang++ is a link to clang. Remove it and reconstruct rm "$TMPDIR/bin/clang++${HOST_EXE}" ln -sf "clang${LLVM_VERSION_WITHOUT_DOT}${HOST_EXE}" "$TMPDIR/bin/clang${LLVM_VERSION_WITHOUT_DOT}++${HOST_EXE}" else mv "$TMPDIR/bin/clang++${HOST_EXE}" "$TMPDIR/bin/clang$LLVM_VERSION_WITHOUT_DOT++${HOST_EXE}" fi TARGET_FLAG="-target $LLVM_TARGET" CLANG_FLAGS="$TARGET_FLAG --sysroot \`dirname \$0\`/../sysroot" cat > "$TMPDIR/bin/clang" < "$TMPDIR/bin/clang++" < "$TMPDIR/bin/clang.cmd" < "$TMPDIR/bin/clang++.cmd" <