在android下进行原生C/C++应用程序开发,通常使用ndk-build脚本编译源代码,但是对于一些第三方库,采用ndk-build编译却是不太方便。我之前有些项目采用了CMake构建系统,现在希望把这些库拿到android下使用,因此想是否可以仍然采用CMake构建系统。本质上,ndk就是一套交叉编译工具链,加上一些方便使用的脚本,而CMake对交叉编译支持的很好,所以从理论上是可行的。上网查了一下,发现已经有老外做了这方面的工作,在此借用一下,以备今后参考。步骤如下:
1. 创建gcc-android文件,文件内容如下:
#!/bin/bash
# Android gcc/g++ wrapper
#
# As android uses completely hacked and gutted gcc, it also
# uses -nostdlib, so for the linking phase we must expilictly
# specify crtbegin, crtend and friends. => We can't just do
# with LDFLAGS. :-(
#
# set DRY_RUN=1 for dry run
# set V=1 for verbose run
V=1
if [ -z $CROSS_PREFIX ]; then
echo "source android-build-env first!"
exit 1
fi
REAL_CC="${CROSS_PREFIX}gcc"
REAL_CXX="${CROSS_PREFIX}g++"
# Inspired by ndk-wrappers:
COMMON_FLAGS="--sysroot=$SYSROOT -march=armv5te -mtune=xscale -msoft-float -mthumb-interwork -ffunction-sections -funwind-tables -fstack-protector -fno-short-enums -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -DANDROID"
CFLAGS="${COMMON_FLAGS}"
CXXFLAGS="${COMMON_FLAGS} -fno-exceptions -fno-rtti"
TARGET_LIBGCC=`${CROSS_PREFIX}gcc -mthumb-interwork -print-libgcc-file-name`
# Test if we're wrapping gcc or g++
THIS_SCRIPT=`basename "$0"`
if [[ "$THIS_SCRIPT" =~ 'gcc' ]]; then
WRAPPED="$REAL_CC"
COMPILE_FLAGS="$CFLAGS"
elif [[ "$THIS_SCRIPT" =~ 'g++' ]]; then
WRAPPED="$REAL_CXX"
COMPILE_FLAGS="$CXXFLAGS"
else
echo "Wrong script name - matches neither '^gcc' nor '^g++'."
exit 2
fi
# Determine what mode (link, compile, nothing) we're in
LINK=1
COMPILE=0SHARED=0for ARG in "$@"; docase "$ARG" in# Preprocess-only (-E) and don't assemble (-S) mean the same as -c for us - the same CFLAGS are needed-c|-S|-E)LINK=0;;*.c|*.cpp|*.c++|*.cxx)COMPILE=1;;# This is broken: gcc -c src.c -o object.o# *.o)# LINK=1# ;;-shared)SHARED=1;;-static)echo "$0: Static executables not supported by this wrapper."exit 5;;-v)LINK=0COMPILE=0break;;esacdoneif [ $# -eq 0 ]; thenCOMPILE=0LINK=0fifunction verbose_command{if [ "$V" = "1" -o "$DRY_RUN" = "1" ]; thenecho "$@"fiif [ "$DRY_RUN" != "1" ]; then"$@"fi}# Compile sourcefunction compile{# That's easyverbose_command "$WRAPPED" $COMPILE_FLAGS "$@"}# Link a binaryfunction link{# TODO: Separate libraries, sources and other arguments# Idea: read args till hitting sources -> that's USER_LIBS# rest is USER_OBJECTS, ignore USER_ARGSUSER_LIBS=""USER_OBJECTS=""USER_ARGS=""OBJECTS_HIT=0for ARG in "$@"; doif [ $OBJECTS_HIT -eq 0 ]; then# Test if ARG is a libif [[ "$ARG" == *.o ]]; then# is an objectOBJECTS_HIT=1USER_OBJECTS="$USER_OBJECTS $ARG"else# a lib or an early paramUSER_LIBS="$USER_LIBS $ARG"fielse# We already reached objects, stuff all into USER_OBJECTSUSER_OBJECTS="$USER_OBJECTS $ARG"fidone# Mess starts hereif [ $SHARED -eq 1 ]; then# TODO: Remove -shared from args# Building a shared libraryLD_PREFIX="--sysroot=$SYSROOT -nostdlib -Wl,-shared,-Bsymbolic"LD_BEGIN="$SYSROOT/usr/lib/libc.so $SYSROOT/usr/lib/libm.so"# user objects# user dyn. libsLD_END="-Wl,--no-undefined -Wl,-rpath-link=$SYSROOT/usr/lib $TARGET_LIBGCC"verbose_command "$WRAPPED" $LD_PREFIX $USER_OBJECTS $USER_LIBS $LD_BEGIN $LD_END $USER_ARGSelse# Building dynamic executableLD_PREFIX="--sysroot=$SYSROOT -nostdlib -Bdynamic -Wl,-dynamic-linker,/system/bin/linker -Wl,--gc-sections -Wl,-z,nocopyreloc"# STLport static lib explodes here, needs to come after objects (??)LD_BEGIN="$SYSROOT/usr/lib/libc.so $SYSROOT/usr/lib/libm.so $SYSROOT/usr/lib/crtbegin_dynamic.o"# user objects# user dyn. libsLD_END="-Wl,--no-undefined -Wl,-rpath-link=$SYSROOT/usr/lib $TARGET_LIBGCC $SYSROOT/usr/lib/crtend_android.o"verbose_command "$WRAPPED" $LD_PREFIX $LD_BEGIN $USER_OBJECTS $USER_LIBS $LD_END $USER_ARGSfi}if [ $COMPILE -eq 0 -a $LINK -eq 0 ]; then# No special handling needed, call $WRAPPEDverbose_command "$WRAPPED" "$@"fi# TODO: support link+compileif [ $COMPILE -eq 1 -a $LINK -eq 1 ]; thenecho "$0: Link and compile in one step is not supported by this wrapper."exit 4fiif [ $COMPILE -eq 1 ]; thencompile "$@"elif [ $LINK -eq 1 ]; thenlink "$@"elseecho "$0: Internal error: Uknown compiler mode."exit 3fi
export ANDROID_NDK_ROOT="$HOME/android/android-ndk-r4"export ANDROID_GCC_WRAPPERS="$HOME/android/ex/androidcodes/cmaketest/script"export PATH="$ANDROID_GCC_WRAPPERS:$ANDROID_NDK_ROOT/build/prebuilt/linux-x86/arm-eabi-4.2.1/bin/:$PATH"export CROSS_PREFIX="arm-eabi-"export SYSROOT="$ANDROID_NDK_ROOT/build/platforms/android-4/arch-arm"# The config is specified in $ANDROID_NDK_ROOT/build/toolchains/arm-eabi-4.2.1/setup.mk# and $ANDROID_NDK_ROOT/build/core/build-*.mkexport MAKE="make"# Use android wrappersexport CC="gcc-android"export CXX="g++-android"export LD="deliberatey-undefined-do-not-use-directly"export CPP="${CROSS_PREFIX}gcc -E"export AS="${CROSS_PREFIX}as"export OBJCOPY="${CROSS_PREFIX}objcopy"export OBJDUMP="${CROSS_PREFIX}objdump"export STRIP="${CROSS_PREFIX}strip"export RANLIB="${CROSS_PREFIX}ranlib"export CCLD="${CROSS_PREFIX}gcc"export AR="${CROSS_PREFIX}ar"