使用CMake构建android原生库

来源:互联网 发布:linux sftp 上传文件 编辑:程序博客网 时间:2024/06/06 12:57

在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 "$@"; 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 "$@"
    fi
    if [ "$DRY_RUN" != "1" ]; then
        "$@"
    fi
}
# Compile source
function compile
{
    # That's easy
    verbose_command "$WRAPPED" $COMPILE_FLAGS "$@"
}
# 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 "$@"; 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" "$@"
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 "$@"
elif [ $LINK -eq 1 ]; then
    link "$@"
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之前,执行source android-build-env,设置相关环境变量。
为此,我写了一个完整的demo,供参考: http://androidcodes.googlecode.com/svn/trunk/cmaketest
0 0
原创粉丝点击