在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=0 SHARED=0 for ARG in "[email protected]"; do case "$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=0 COMPILE=0 break ;; esac done if [ $# -eq 0 ]; then COMPILE=0 LINK=0 fi function verbose_command { if [ "$V" = "1" -o "$DRY_RUN" = "1" ]; then echo "[email protected]" fi if [ "$DRY_RUN" != "1" ]; then "[email protected]" fi } # Compile source function compile { # That's easy verbose_command "$WRAPPED" $COMPILE_FLAGS "[email protected]" } # Link a binary function link { # TODO: Separate libraries, sources and other arguments # Idea: read args till hitting sources -> that's USER_LIBS # rest is USER_OBJECTS, ignore USER_ARGS USER_LIBS="" USER_OBJECTS="" USER_ARGS="" OBJECTS_HIT=0 for ARG in "[email protected]"; do if [ $OBJECTS_HIT -eq 0 ]; then # Test if ARG is a lib if [[ "$ARG" == *.o ]]; then # is an object OBJECTS_HIT=1 USER_OBJECTS="$USER_OBJECTS $ARG" else # a lib or an early param USER_LIBS="$USER_LIBS $ARG" fi else # We already reached objects, stuff all into USER_OBJECTS USER_OBJECTS="$USER_OBJECTS $ARG" fi done # Mess starts here if [ $SHARED -eq 1 ]; then # TODO: Remove -shared from args # Building a shared library LD_PREFIX="--sysroot=$SYSROOT -nostdlib -Wl,-shared,-Bsymbolic" LD_BEGIN="$SYSROOT/usr/lib/libc.so $SYSROOT/usr/lib/libm.so" # user objects # user dyn. libs LD_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_ARGS else # Building dynamic executable LD_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. libs LD_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_ARGS fi } if [ $COMPILE -eq 0 -a $LINK -eq 0 ]; then # No special handling needed, call $WRAPPED verbose_command "$WRAPPED" "[email protected]" fi # TODO: support link+compile if [ $COMPILE -eq 1 -a $LINK -eq 1 ]; then echo "$0: Link and compile in one step is not supported by this wrapper." exit 4 fi if [ $COMPILE -eq 1 ]; then compile "[email protected]" elif [ $LINK -eq 1 ]; then link "[email protected]" else echo "$0: Internal error: Uknown compiler mode." exit 3 fi

2. 为gcc-android创建一个软链接g++-android 3. 创建 android-build-env文件,文件内容如下:
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-*.mk export MAKE="make" # Use android wrappers export 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"
(请根据实际的路径修改脚本) 3. 在运行cmake之前,执行sourceandroid-build-env,设置相关环境变量。 为此,我写了一个完整的demo,供参考:http://androidcodes.googlecode.com/svn/trunk/cmaketest

更多相关文章

  1. Android运行时ART加载OAT文件的过程分析
  2. 批量处理ios破解后的资源文件为android所用
  3. Android中的R.java文件你知多少
  4. 如何给你的Android 安装文件(APK)瘦身(一)
  5. 在Android使用XML文件控制按钮文字在各种状态下的颜色

随机推荐

  1. Android(安卓)EditText自定义样式的方法
  2. Android之Animation全介绍
  3. Android浏览器插件开发-Log
  4. 为TextView设置边框
  5. android浏览器下a/input等元素获得焦点时
  6. 如何设置Android中控件的颜色透明度
  7. ListView-BaseAdapter
  8. Android专项测试监控资源
  9. android进程间通信:使用AIDL
  10. 动态Android编程