Andoid NDK编译分析

MSM8909交叉工具链使用:

LittleKernel : prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/bin/
Kernel : prebuilts/gcc/linux-x86/arm/arm-eabi-4.8/bin/
Framework : clang+llvm

Clang的发展

libc++.so是针对Clang编译器特别重写的C++标准库
而libstdc++.so则是GCC的对应C++标准库
从r11开始建议大家切换到Clang,并且把GCC标记为deprecated,将GCC版本锁定在GCC4.9不再更新;
从r13起,默认使用Clang 进行编译,但是暂时也没有把 GCC 删掉;
在r17中宣称不再支持GCC并在后续的r18中删掉GCC,具体可见NDK的版本历史。

Clang主要完成编译前端工作:词法分析、语法分析、语义分析和生成中间代码
LLVM(Low Level Virtual Machine)完成:代码优化、生成目标程序

Native编译的三种方法:

1.ndk-build脚本:通过脚本和Application.mk、Android.mk组织工具链生成so

1.1 ndk-build脚本实际调用的build-local.mk

$GNUMAKE -f $PROGDIR/core/build-local.mk "$@"

1.2 buil-local.mk首先引入init.mk以初始化编译变量

include $(NDK_ROOT)/build/core/init.mk

init.mk中给BUILD_SYSTEM等重要变量赋值

BUILD_SYSTEM := $(NDK_ROOT)/build/core

添加所有支持的编译工具链,对每个config.mk执行add-toolchain.mk

TOOLCHAIN_CONFIGS := $(wildcard $(NDK_ROOT)/build/core/toolchains/*/config.mk)
$(foreach _config_mk,$(TOOLCHAIN_CONFIGS),\
  $(eval include $(BUILD_SYSTEM)/add-toolchain.mk)\
)

添加支持的Android Platform版本,且对每个platform都执行add-platform.mk(需要注意AOSP的NDK_PLATFORMS_ROOT应该在$TOP/development/ndk/platforms,只有release的ndk才使用下面的查找方法):

NDK_PLATFORMS_ROOT := $(strip $(wildcard $(NDK_ROOT)/platforms))
$(foreach _platform,$(NDK_ALL_PLATFORMS),\
  $(eval include $(BUILD_SYSTEM)/add-platform.mk)\
)

1.3 随后buil-local.mk在当前目录下递归寻找AndroidManifest.xml或者jni/Android.mk文件,成功则将NDK_PROJECT_PATH设置为当前目录:

`NDK_PROJECT_PATH := .

1.4 如果目录下没有Application.mk则使用默认Application.mk

ifndef NDK_APPLICATION_MK
    NDK_APPLICATION_MK := $(NDK_ROOT)/build/core/default-application.mk
endif

默认的Application.mk主要作用为赋值:

APP_PROJECT_PATH := $(NDK_PROJECT_PATH)
APP_BUILD_SCRIPT := $(APP_PROJECT_PATH)/jni/Android.mk

1.5 build-local.mk包含build/core/add-application.mk,为APP_PLATFORM、APP_ABI、APP_CFLAGS等赋值

include $(BUILD_SYSTEM)/add-application.mk

1.6 最后build-local.mk通过build/core/build-all.mk开始编译

include $(BUILD_SYSTEM)/build-all.mk

1.7 build-all.mk中对于每个app调用setup-app.mk

$(foreach _app,$(NDK_APPS),\
  $(eval include $(BUILD_SYSTEM)/setup-app.mk)\
)

setup-app.mk中对每个abi调用setup-abi.mk

$(foreach _abi,$(NDK_APP_ABI),\
	$(eval TARGET_ARCH_ABI := $(_abi))\
	$(eval include $(BUILD_SYSTEM)/setup-abi.mk) \
)

setup-abi中调用setup-toolchain.mk,根据platform/abi确定交叉工具链

从MSM8909的ndk(R10e)的setup-toolchain.mk中看,优先工具链优先级gcc->llvm->clang

而从r19c的ndk中看,优先选择clang作为编译工具链

2.CMake:新版AndroidStudio优选方案,通过CMakeLists组织工具链生成so
拿X86上的AS自动生成的android.toolchain.cmake为例,先根据CPU架构设置编译链

if(ANDROID_ABI STREQUAL armeabi-v7a)
  set(ANDROID_SYSROOT_ABI arm)
  set(ANDROID_TOOLCHAIN_NAME arm-linux-androideabi)
  set(CMAKE_SYSTEM_PROCESSOR armv7-a)
  set(ANDROID_LLVM_TRIPLE armv7-none-linux-androideabi)

ANDROID_TOOLCHAIN_NAME变量实际并不是使用的编译链,只影响library的路径

set(ANDROID_HOST_TAG windows-x86_64)

set(ANDROID_TOOLCHAIN_ROOT
  "${ANDROID_NDK}/toolchains/llvm/prebuilt/${ANDROID_HOST_TAG}")

list(APPEND CMAKE_SYSTEM_LIBRARY_PATH
  "/usr/lib/${ANDROID_TOOLCHAIN_NAME}/${ANDROID_PLATFORM_LEVEL}")

其中ANDROID_PLATFORM_LEVEL是使用的Android版本,不同的安卓版本,动态库可能有微小差别

实际编译使用的工具链为clang:

set(ANDROID_C_COMPILER
  "${ANDROID_TOOLCHAIN_ROOT}/bin/clang${ANDROID_TOOLCHAIN_SUFFIX}")
set(ANDROID_CXX_COMPILER
  "${ANDROID_TOOLCHAIN_ROOT}/bin/clang++${ANDROID_TOOLCHAIN_SUFFIX}")
set(ANDROID_ASM_COMPILER
  "${ANDROID_TOOLCHAIN_ROOT}/bin/clang${ANDROID_TOOLCHAIN_SUFFIX}")

3.直接调用toolchain:直接调用clang或者gcc进行编译,比较少用,AOSP的build系统就是一个例子

注意:MSM8909 Android N工程虽然有ndk(R10e),实际编译却直接调用clang工具链:

对应于任何Android.mk,将包含build/core/config.mk中的

BUILD_STATIC_LIBRARY、BUILD_SHARED_LIBRARY、BUILD_EXECUTABLE,而这些变量为一些mk文件

BUILD_STATIC_LIBRARY:= $(BUILD_SYSTEM)/static_library.mk
BUILD_SHARED_LIBRARY:= $(BUILD_SYSTEM)/shared_library.mk
BUILD_EXECUTABLE:= $(BUILD_SYSTEM)/executable.mk

这些文件最后都会包含build/core/binary.mk:

首先确定ndk使用的platform的位置:

HISTORICAL_NDK_VERSIONS_ROOT := $(TOPDIR)prebuilts/ndk
my_ndk_sysroot := $(HISTORICAL_NDK_VERSIONS_ROOT)/current/platforms/android-$(LOCAL_SDK_VERSION)/arch-$(TARGET_$(LOCAL_2ND_ARCH_VAR_PREFIX)ARCH)

同时也确定了使用clang作为工具链:

build/core/config.mk通过包含clang/versions.mk和clang/config.mk确定
CLANG_CXX = /prebuilts/clang/host/linux-x86/clang-2690385
build/core/envsetup.mk中:
USE_CLANG_PLATFORM_BUILD := true

my_clang := true
my_cxx := $(CLANG_CXX)
PRIVATE_CXX := $(my_cxx)

build/core/definitions.mk中定义了很多编译函数:
define transform-cpp-to-o
@echo "target $(PRIVATE_ARM_MODE) C++: $(PRIVATE_MODULE) <= $<"
@mkdir -p $(dir $@)
$(hide) $(RELATIVE_PWD) $(PRIVATE_CXX) \
    $(addprefix -I , $(PRIVATE_C_INCLUDES)) \
    $(shell cat $(PRIVATE_IMPORT_INCLUDES)) \
    $(addprefix -isystem ,\
        $(if $(PRIVATE_NO_DEFAULT_COMPILER_FLAGS),, \
            $(filter-out $(PRIVATE_C_INCLUDES), \
                $(PRIVATE_TARGET_PROJECT_INCLUDES) \
                $(PRIVATE_TARGET_C_INCLUDES)))) \
    -c \
    $(if $(PRIVATE_NO_DEFAULT_COMPILER_FLAGS),, \
        $(PRIVATE_TARGET_GLOBAL_CFLAGS) \
        $(PRIVATE_TARGET_GLOBAL_CPPFLAGS) \
        $(PRIVATE_ARM_CFLAGS) \
     ) \
    $(PRIVATE_RTTI_FLAG) \
    $(PRIVATE_CFLAGS) \
    $(PRIVATE_CPPFLAGS) \
    $(PRIVATE_DEBUG_CFLAGS) \
    $(PRIVATE_CFLAGS_NO_OVERRIDE) \
    $(PRIVATE_CPPFLAGS_NO_OVERRIDE) \
    -MD -MF $(patsubst %.o,%.d,$@) -o $@ $<
$(transform-d-to-p)
endef

在build/core/binary.mk被调用
ifneq ($(strip $(cpp_objects)),)
$(cpp_objects): $(intermediates)/%.o: \
	$(TOPDIR)$(LOCAL_PATH)/%$(LOCAL_CPP_EXTENSION) \
	$(my_additional_dependencies)
	$(transform-$(PRIVATE_HOST)cpp-to-o)
endif
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值