Android编译系统环境初始化过程分析3
来源:互联网 发布:网络女主播说唱歌曲 编辑:程序博客网 时间:2024/05/24 04:20
我们再来看函数import-products的实现,它定义在文件build/core/product.mk中,如下所示:
- #
- # $(1): product makefile list
- #
- #TODO: check to make sure that products have all the necessary vars defined
- define import-products
- $(call import-nodes,PRODUCTS,$(1),$(_product_var_list))
- endef
- _product_var_list := \
- PRODUCT_NAME \
- PRODUCT_MODEL \
- PRODUCT_LOCALES \
- PRODUCT_AAPT_CONFIG \
- PRODUCT_AAPT_PREF_CONFIG \
- PRODUCT_PACKAGES \
- PRODUCT_PACKAGES_DEBUG \
- PRODUCT_PACKAGES_ENG \
- PRODUCT_PACKAGES_TESTS \
- PRODUCT_DEVICE \
- PRODUCT_MANUFACTURER \
- PRODUCT_BRAND \
- PRODUCT_PROPERTY_OVERRIDES \
- PRODUCT_DEFAULT_PROPERTY_OVERRIDES \
- PRODUCT_CHARACTERISTICS \
- PRODUCT_COPY_FILES \
- PRODUCT_OTA_PUBLIC_KEYS \
- PRODUCT_EXTRA_RECOVERY_KEYS \
- PRODUCT_PACKAGE_OVERLAYS \
- DEVICE_PACKAGE_OVERLAYS \
- PRODUCT_TAGS \
- PRODUCT_SDK_ADDON_NAME \
- PRODUCT_SDK_ADDON_COPY_FILES \
- PRODUCT_SDK_ADDON_COPY_MODULES \
- PRODUCT_SDK_ADDON_DOC_MODULES \
- PRODUCT_DEFAULT_WIFI_CHANNELS \
- PRODUCT_DEFAULT_DEV_CERTIFICATE \
- PRODUCT_RESTRICT_VENDOR_FILES \
- PRODUCT_VENDOR_KERNEL_HEADERS \
- PRODUCT_FACTORY_RAMDISK_MODULES \
- PRODUCT_FACTORY_BUNDLE_MODULES
函数import-nodes定义在文件build/core/node_fns.mk中,如下所示:
- #
- # $(1): output list variable name, like "PRODUCTS" or "DEVICES"
- # $(2): list of makefiles representing nodes to import
- # $(3): list of node variable names
- #
- define import-nodes
- $(if \
- $(foreach _in,$(2), \
- $(eval _node_import_context := _nic.$(1).[[$(_in)]]) \
- $(if $(_include_stack),$(eval $(error ASSERTION FAILED: _include_stack \
- should be empty here: $(_include_stack))),) \
- $(eval _include_stack := ) \
- $(call _import-nodes-inner,$(_node_import_context),$(_in),$(3)) \
- $(call move-var-list,$(_node_import_context).$(_in),$(1).$(_in),$(3)) \
- $(eval _node_import_context :=) \
- $(eval $(1) := $($(1)) $(_in)) \
- $(if $(_include_stack),$(eval $(error ASSERTION FAILED: _include_stack \
- should be empty here: $(_include_stack))),) \
- ) \
- ,)
- endef
1. 调用函数_import-nodes-inner将参数$2描述的每一个产品Makefile文件加载进来。
2. 调用函数move-var-list将定义在前面所加载的产品Makefile文件里面的由参数$3指定的变量的值分别拷贝到另外一组独立的变量中。
3. 将参数$2描述的每一个产品Makefile文件路径以空格分隔保存在参数$1所描述的变量中,也就是保存在变量PRODUCTS中。
上述第二件事情需要进一步解释一下。由于当前加载的每一个文件都会定义相同的变量,为了区分这些变量,我们需要在这些变量前面加一些前缀。例如,假设加载了build/target/product/full.mk这个产品Makefile文件,它里面定义了以下几个变量:
- # Overrides
- PRODUCT_NAME := full
- PRODUCT_DEVICE := generic
- PRODUCT_BRAND := Android
- PRODUCT_MODEL := Full Android on Emulator
- PRODUCTS.build/target/product/full.mk.PRODUCT_NAME := full
- PRODUCTS.build/target/product/full.mk.PRODUCT_DEVICE := generic
- PRODUCTS.build/target/product/full.mk.PRODUCT_BRAND := Android
- PRODUCTS.build/target/product/full.mk.PRODUCT_MODEL := Full Android on Emulator
回到build/core/config.mk文件中,接下来我们再看BoardConfig.mk文件的加载过程。前面提到,当前要加载的BoardConfig.mk文件由变量TARGET_DEVICE来确定。例如,假设我们在运行lunch命令时,输入的文本为full-eng,那么build/target/product/full.mk就会被加载,并且我们得到TARGET_DEVICE的值就为generic,接下来加载的BoradConfig.mk文件就会在build/target/board/generic目录中找到。
BoardConfig.mk文件定义的信息可以参考build/target/board/generic/BoardConfig.mk文件的内容,如下所示:
- # config.mk
- #
- # Product-specific compile-time definitions.
- #
- # The generic product target doesn't have any hardware-specific pieces.
- TARGET_NO_BOOTLOADER := true
- TARGET_NO_KERNEL := true
- TARGET_ARCH := arm
- # Note: we build the platform images for ARMv7-A _without_ NEON.
- #
- # Technically, the emulator supports ARMv7-A _and_ NEON instructions, but
- # emulated NEON code paths typically ends up 2x slower than the normal C code
- # it is supposed to replace (unlike on real devices where it is 2x to 3x
- # faster).
- #
- # What this means is that the platform image will not use NEON code paths
- # that are slower to emulate. On the other hand, it is possible to emulate
- # application code generated with the NDK that uses NEON in the emulator.
- #
- TARGET_ARCH_VARIANT := armv7-a
- TARGET_CPU_ABI := armeabi-v7a
- TARGET_CPU_ABI2 := armeabi
- ARCH_ARM_HAVE_TLS_REGISTER := true
- HAVE_HTC_AUDIO_DRIVER := true
- BOARD_USES_GENERIC_AUDIO := true
- # no hardware camera
- USE_CAMERA_STUB := true
- # Enable dex-preoptimization to speed up the first boot sequence
- # of an SDK AVD. Note that this operation only works on Linux for now
- ifeq ($(HOST_OS),linux)
- ifeq ($(WITH_DEXPREOPT),)
- WITH_DEXPREOPT := true
- endif
- endif
- # Build OpenGLES emulation guest and host libraries
- BUILD_EMULATOR_OPENGL := true
- # Build and enable the OpenGL ES View renderer. When running on the emulator,
- # the GLES renderer disables itself if host GL acceleration isn't available.
- USE_OPENGL_RENDERER := true
再回到build/core/config.mk文件中,它最后加载build/core/dumpvar.mk文件。加载build/core/dumpvar.mk文件是为了生成make目标,以便可以对这些目标进行操作。例如,在我们这个情景中,我们要执行的make目标是dumpvar-TARGET_DEVICE,因此在加载build/core/dumpvar.mk文件的过程中,就会生成dumpvar-TARGET_DEVICE目标。
文件build/core/dumpvar.mk的内容也比较多,这里我们只关注生成make目标相关的逻辑:
- ......
- # The "dumpvar" stuff lets you say something like
- #
- # CALLED_FROM_SETUP=true \
- # make -f config/envsetup.make dumpvar-TARGET_OUT
- # or
- # CALLED_FROM_SETUP=true \
- # make -f config/envsetup.make dumpvar-abs-HOST_OUT_EXECUTABLES
- #
- # The plain (non-abs) version just dumps the value of the named variable.
- # The "abs" version will treat the variable as a path, and dumps an
- # absolute path to it.
- #
- dumpvar_goals := \
- $(strip $(patsubst dumpvar-%,%,$(filter dumpvar-%,$(MAKECMDGOALS))))
- ifdef dumpvar_goals
- ifneq ($(words $(dumpvar_goals)),1)
- $(error Only one "dumpvar-" goal allowed. Saw "$(MAKECMDGOALS)")
- endif
- # If the goal is of the form "dumpvar-abs-VARNAME", then
- # treat VARNAME as a path and return the absolute path to it.
- absolute_dumpvar := $(strip $(filter abs-%,$(dumpvar_goals)))
- ifdef absolute_dumpvar
- dumpvar_goals := $(patsubst abs-%,%,$(dumpvar_goals))
- ifneq ($(filter /%,$($(dumpvar_goals))),)
- DUMPVAR_VALUE := $($(dumpvar_goals))
- else
- DUMPVAR_VALUE := $(PWD)/$($(dumpvar_goals))
- endif
- dumpvar_target := dumpvar-abs-$(dumpvar_goals)
- else
- DUMPVAR_VALUE := $($(dumpvar_goals))
- dumpvar_target := dumpvar-$(dumpvar_goals)
- endif
- .PHONY: $(dumpvar_target)
- $(dumpvar_target):
- @echo $(DUMPVAR_VALUE)
- endif # dumpvar_goals
- ......
上述代码的逻辑很简单,例如,在我们这个情景中,指定的make目标为dumpvar-TARGET_DEVICE,那么就会得到变量DUMPVAR_VALUE的值为$(TARGET_DEVICE)。TARGET_DEVICE的值在前面已经被设置为“generic”,因此变量DUMPVAR_VALUE的值就等于“generic”。此外,变量dumpvar_target的被设置为“dumpvar-TARGET_DEVICE”。最后我们就可以得到以下的make规则:
- .PHONY dumpvar-TARGET_DEVICE
- dumpvar-TARGET_DEVICE:
- @echo generic
接下来我们还要继续分析在build/envsetup.sh文件中定义的函数check_variant的实现,如下所示:
- VARIANT_CHOICES=(user userdebug eng)
- # check to see if the supplied variant is valid
- function check_variant()
- {
- for v in ${VARIANT_CHOICES[@]}
- do
- if [ "$v" = "$1" ]
- then
- return 0
- fi
- done
- return 1
- }
最后,我们再来分析在build/envsetup.sh文件中定义的函数printconfig的实现,如下所示:
- function printconfig()
- {
- T=$(gettop)
- if [ ! "$T" ]; then
- echo "Couldn't locate the top of the tree. Try setting TOP." >&2
- return
- fi
- get_build_var report_config
- }
我们跳过前面build/core/config.mk和build/core/envsetup.mk等文件对目标产品Makefile文件的加载,直接跳到build/core/dumpvar.mk文件来查看与report_config这个make目标相关的逻辑:
- ......
- dumpvar_goals := \
- $(strip $(patsubst dumpvar-%,%,$(filter dumpvar-%,$(MAKECMDGOALS))))
- .....
- ifneq ($(dumpvar_goals),report_config)
- PRINT_BUILD_CONFIG:=
- endif
- ......
- ifneq ($(PRINT_BUILD_CONFIG),)
- HOST_OS_EXTRA:=$(shell python -c "import platform; print(platform.platform())")
- $(info ============================================)
- $(info PLATFORM_VERSION_CODENAME=$(PLATFORM_VERSION_CODENAME))
- $(info PLATFORM_VERSION=$(PLATFORM_VERSION))
- $(info TARGET_PRODUCT=$(TARGET_PRODUCT))
- $(info TARGET_BUILD_VARIANT=$(TARGET_BUILD_VARIANT))
- $(info TARGET_BUILD_TYPE=$(TARGET_BUILD_TYPE))
- $(info TARGET_BUILD_APPS=$(TARGET_BUILD_APPS))
- $(info TARGET_ARCH=$(TARGET_ARCH))
- $(info TARGET_ARCH_VARIANT=$(TARGET_ARCH_VARIANT))
- $(info HOST_ARCH=$(HOST_ARCH))
- $(info HOST_OS=$(HOST_OS))
- $(info HOST_OS_EXTRA=$(HOST_OS_EXTRA))
- $(info HOST_BUILD_TYPE=$(HOST_BUILD_TYPE))
- $(info BUILD_ID=$(BUILD_ID))
- $(info OUT_DIR=$(OUT_DIR))
- $(info ============================================)
- endif
至此,我们就分析完成Android编译系统环境的初始化过程了。从分析的过程可以知道,Android编译系统环境是由build/core/config.mk、build/core/envsetup.mk、build/core/product_config.mk、AndroidProducts.mk和BoardConfig.mk等文件来完成的。这些mk文件涉及到非常多的细节,而我们这里只提供了一个大体的骨架和脉络,希望能够起到抛砖引玉的作用。
- Android编译系统环境初始化过程分析
- Android编译系统环境初始化过程分析
- Android编译系统环境初始化过程分析
- Android编译系统环境初始化过程分析
- Android编译系统环境初始化过程分析
- Android编译系统环境初始化过程分析
- Android编译系统环境初始化过程分析
- Android编译系统环境初始化过程分析
- Android编译系统环境初始化过程分析
- Android编译系统环境初始化过程分析
- Android编译系统环境初始化过程分析
- Android编译系统环境初始化过程分析
- Android编译系统环境初始化过程分析
- Android编译系统环境初始化过程分析
- Android编译系统环境初始化过程分析
- Android编译系统环境初始化过程分析3
- Android编译系统环境初始化过程分析2
- Android编译系统环境初始化过程分析 1
- 华为OJ(计算日期到天数转换)
- 阿里校招 数据分析师 笔试题
- 设计模式之桥接
- java学习记录笔记--继承,super,Object类
- java 字节流和字符流的区别 转载
- Android编译系统环境初始化过程分析3
- C++中的智能指针
- Eclipse打开-报错:发现了以元素 ‘d:skin’ 开头的无效内容。此处不应含有子元素(解决方法)
- Android编译系统环境初始化过程分析 1
- 快学Scala习题解答—第三章 数组相关操作
- 这就是web app跟原生app的差别 (太经典了,说到骨子了去)
- 【LeetCode】169_Majority Element
- 求所有最大公共子序列的算法实现(转)
- Java中正则表达式和常用的Math、Random、System、BigInteger、BigDecimal、Date/DateFormat、Calendar类的使用