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