作者:唐攀,华清远见嵌入式培训中心讲师。

通过上篇文章,我们分析了编译android时source build/envsetup.sh和lunch命令,在执行完上述两个命令后, 我们就可以进行编译android了。

1、 make

执行make命令的结果就是去执行当前目录下的Makefile文件,我们来看下它的内容:

1 ### DO NOT EDIT THIS FILE ###
2 include build/core/main.mk
3 ### DO NOT EDIT THIS FILE ###

呵呵,看到上面 的内容,我们都会笑,这是我见过最简单的Makefile了,我们再看下build/core/main.mk

在main.mk里,定义了变量TOPDIR,TOP为当前目录,BUILD_SYSTEM为build/core目录。

在49行,包含了build/core/config.mk文件。

后面的代码是check环境 变量,所有的Makefile都通过build/core/main.mk这个文件组织在一起,它定义了一个默认goals:droid,当我们在TOP目录下,敲Make实际上就等同于我们执行make droid。当Make include所有的文件,完成对所有make我文件的解析以后就会寻找生成droid的规则,依次生成它的依赖,直到所有满足的模块被编译好,然后使用相应的工具打包成相应的img。这儿不是我们的重点,不再多说。

2、 build/core/config.mk

该文件被main.mk包含。

定义了以下环境变量:

16 SRC_HEADERS := \
17 $(TOPDIR)system/core/include \
18 $(TOPDIR)hardware/libhardware/include \
19 $(TOPDIR)hardware/libhardware_legacy/include \
20 $(TOPDIR)hardware/ril/include \
21 $(TOPDIR)dalvik/libnativehelper/include \
22 $(TOPDIR)frameworks/base/include \
23 $(TOPDIR)frameworks/base/opengl/include \
24 $(TOPDIR)external/skia/include
25 SRC_HOST_HEADERS:=$(TOPDIR)tools/include
26 SRC_LIBRARIES:= $(TOPDIR)libs
27 SRC_SERVERS:= $(TOPDIR)servers
28 SRC_TARGET_DIR := $(TOPDIR)build/target
29 SRC_API_DIR := $(TOPDIR)frameworks/base/api
.....然后定义了下面几个重要的编译命令 43 CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.mk
44 BUILD_HOST_STATIC_LIBRARY:= $(BUILD_SYSTEM)/host_static_library.mk
45 BUILD_HOST_SHARED_LIBRARY:= $(BUILD_SYSTEM)/host_shared_library.mk
46 BUILD_STATIC_LIBRARY:= $(BUILD_SYSTEM)/static_library.mk
47 BUILD_RAW_STATIC_LIBRARY := $(BUILD_SYSTEM)/raw_static_library.mk
48 BUILD_SHARED_LIBRARY:= $(BUILD_SYSTEM)/shared_library.mk
49 BUILD_EXECUTABLE:= $(BUILD_SYSTEM)/executable.mk
50 BUILD_RAW_EXECUTABLE:= $(BUILD_SYSTEM)/raw_executable.mk
51 BUILD_HOST_EXECUTABLE:= $(BUILD_SYSTEM)/host_executable.mk
52 BUILD_PACKAGE:= $(BUILD_SYSTEM)/package.mk
53 BUILD_HOST_PREBUILT:= $(BUILD_SYSTEM)/host_prebuilt.mk
54 BUILD_PREBUILT:= $(BUILD_SYSTEM)/prebuilt.mk
55 BUILD_MULTI_PREBUILT:= $(BUILD_SYSTEM)/multi_prebuilt.mk
56 BUILD_JAVA_LIBRARY:= $(BUILD_SYSTEM)/java_library.mk
57 BUILD_STATIC_JAVA_LIBRARY:= $(BUILD_SYSTEM)/static_java_library.mk
58 BUILD_HOST_JAVA_LIBRARY:= $(BUILD_SYSTEM)/host_java_library.mk
59 BUILD_DROIDDOC:= $(BUILD_SYSTEM)/droiddoc.mk
60 BUILD_COPY_HEADERS := $(BUILD_SYSTEM)/copy_headers.mk
61 BUILD_KEY_CHAR_MAP := $(BUILD_SYSTEM)/key_char_map.mk

上述命令变量其实是对应的mk文件名,所有的Android.mk文件里基本上都包含上述命令变量,如:

CLEAR_VARS:用来清除之前定义的环境变量

BUILD_SHARED_LIBRARY:用来指定编译动态库过程

109 # ---------------------------------------------------------------
110 # Define most of the global variables. These are the ones that
111 # are specific to the user's build configuration.
112 include $(BUILD_SYSTEM)/envsetup.mk
113
114 # Boards may be defined under $(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)
115 # or under vendor/*/$(TARGET_DEVICE). Search in both places, but
116 # make sure only one exists.
117 # Real boards should always be associated with an OEM vendor.
118 board_config_mk := \
119 $(strip $(wildcard \
120 $(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)/BoardConfig.mk \
121 vendor/*/$(TARGET_DEVICE)/BoardConfig.mk \
122 ))
123 ifeq ($(board_config_mk),)
124 $(error No config file found for TARGET_DEVICE $(TARGET_DEVICE))
125 endif
126 ifneq ($(words $(board_config_mk)),1)
127 $(error Multiple board config files for TARGET_DEVICE $(TARGET_DEVICE): $(board_config_mk))
128 endif
129 include $(board_config_mk)
130 TARGET_DEVICE_DIR := $(patsubst %/,%,$(dir $(board_config_mk)))
131 board_config_mk :=
112行又包含了另外一个重要的mk文件envsetup.mk,我们来看一下。

3、envsetup.mk

25 ifeq ($(TARGET_PRODUCT),) #判断TARGET_PRODUCT是否为空,
26 ifeq ($(TARGET_SIMULATOR),true)
27 TARGET_PRODUCT := sim
28 else
29 TARGET_PRODUCT := generic
30 endif
31 endif

第25行,判断TARGET_PRODUCT是否为空,根据上一节分析可知,TARGET_PRODUCT=fs100
34 # the variant -- the set of files that are included for a build
35 ifeq ($(strip $(TARGET_BUILD_VARIANT)),)
36 TARGET_BUILD_VARIANT := eng
37 endif
38
39 # Read the product specs so we an get TARGET_DEVICE and other
40 # variables that we need in order to locate the output files.
41 include $(BUILD_SYSTEM)/product_config.mk

在41行又包含了product_config.mk文件,等会我们再分析它,先看下面的

148 # ---------------------------------------------------------------
149 # figure out the output directories
150
151 ifeq (,$(strip $(OUT_DIR)))
152 OUT_DIR := $(TOPDIR)out
153 endif
154
155 DEBUG_OUT_DIR := $(OUT_DIR)/debug
156
157 # Move the host or target under the debug/ directory
158 # if necessary.
159 TARGET_OUT_ROOT_release := $(OUT_DIR)/target
160 TARGET_OUT_ROOT_debug := $(DEBUG_OUT_DIR)/target
161 TARGET_OUT_ROOT := $(TARGET_OUT_ROOT_$(TARGET_BUILD_TYPE))
162
...
184 PRODUCT_OUT := $(TARGET_PRODUCT_OUT_ROOT)/$(TARGET_DEVICE)
187
188 HOST_OUT_EXECUTABLES:= $(HOST_OUT)/bin
189 HOST_OUT_SHARED_LIBRARIES:= $(HOST_OUT)/lib
190 HOST_OUT_JAVA_LIBRARIES:= $(HOST_OUT)/framework
191 HOST_OUT_SDK_ADDON := $(HOST_OUT)/sdk_addon
...
200 TARGET_OUT_INTERMEDIATES := $(PRODUCT_OUT)/obj
201 TARGET_OUT_HEADERS:= $(TARGET_OUT_INTERMEDIATES)/include
202 TARGET_OUT_INTERMEDIATE_LIBRARIES := $(TARGET_OUT_INTERMEDIATES)/lib
203 TARGET_OUT_COMMON_INTERMEDIATES := $(TARGET_COMMON_OUT_ROOT)/obj
204
205 TARGET_OUT := $(PRODUCT_OUT)/system
206 TARGET_OUT_EXECUTABLES:= $(TARGET_OUT)/bin
207 TARGET_OUT_OPTIONAL_EXECUTABLES:= $(TARGET_OUT)/xbin
208 TARGET_OUT_SHARED_LIBRARIES:= $(TARGET_OUT)/lib
209 TARGET_OUT_JAVA_LIBRARIES:= $(TARGET_OUT)/framework
210 TARGET_OUT_APPS:= $(TARGET_OUT)/app
211 TARGET_OUT_KEYLAYOUT := $(TARGET_OUT)/usr/keylayout
212 TARGET_OUT_KEYCHARS := $(TARGET_OUT)/usr/keychars
213 TARGET_OUT_ETC := $(TARGET_OUT)/etc
214 TARGET_OUT_STATIC_LIBRARIES:= $(TARGET_OUT_INTERMEDIATES)/lib
215 TARGET_OUT_NOTICE_FILES:=$(TARGET_OUT_INTERMEDIATES)/NOTICE_FILES
216
217 TARGET_OUT_DATA := $(PRODUCT_OUT)/data
218 TARGET_OUT_DATA_EXECUTABLES:= $(TARGET_OUT_EXECUTABLES)
219 TARGET_OUT_DATA_SHARED_LIBRARIES:= $(TARGET_OUT_SHARED_LIBRARIES)
220 TARGET_OUT_DATA_JAVA_LIBRARIES:= $(TARGET_OUT_JAVA_LIBRARIES)
221 TARGET_OUT_DATA_APPS:= $(TARGET_OUT_DATA)/app
222 TARGET_OUT_DATA_KEYLAYOUT := $(TARGET_OUT_KEYLAYOUT)
223 TARGET_OUT_DATA_KEYCHARS := $(TARGET_OUT_KEYCHARS)
224 TARGET_OUT_DATA_ETC := $(TARGET_OUT_ETC)
225 TARGET_OUT_DATA_STATIC_LIBRARIES:= $(TARGET_OUT_STATIC_LIBRARIES)
226
227 TARGET_OUT_UNSTRIPPED := $(PRODUCT_OUT)/symbols
228 TARGET_OUT_EXECUTABLES_UNSTRIPPED := $(TARGET_OUT_UNSTRIPPED)/system/bin
229 TARGET_OUT_SHARED_LIBRARIES_UNSTRIPPED := $(TARGET_OUT_UNSTRIPPED)/system/lib
230 TARGET_ROOT_OUT_UNSTRIPPED := $(TARGET_OUT_UNSTRIPPED)
231 TARGET_ROOT_OUT_SBIN_UNSTRIPPED := $(TARGET_OUT_UNSTRIPPED)/sbin
232 TARGET_ROOT_OUT_BIN_UNSTRIPPED := $(TARGET_OUT_UNSTRIPPED)/bin
233
234 TARGET_ROOT_OUT := $(PRODUCT_OUT)/root
235 TARGET_ROOT_OUT_BIN := $(TARGET_ROOT_OUT)/bin
236 TARGET_ROOT_OUT_SBIN := $(TARGET_ROOT_OUT)/sbin
237 TARGET_ROOT_OUT_ETC := $(TARGET_ROOT_OUT)/etc
238 TARGET_ROOT_OUT_USR := $(TARGET_ROOT_OUT)/usr
239
240 TARGET_RECOVERY_OUT := $(PRODUCT_OUT)/recovery
241 TARGET_RECOVERY_ROOT_OUT := $(TARGET_RECOVERY_OUT)/root
242
243 TARGET_SYSLOADER_OUT := $(PRODUCT_OUT)/sysloader
244 TARGET_SYSLOADER_ROOT_OUT := $(TARGET_SYSLOADER_OUT)/root
245 TARGET_SYSLOADER_SYSTEM_OUT := $(TARGET_SYSLOADER_OUT)/root/system
246
247 TARGET_INSTALLER_OUT := $(PRODUCT_OUT)/installer
248 TARGET_INSTALLER_DATA_OUT := $(TARGET_INSTALLER_OUT)/data
249 TARGET_INSTALLER_ROOT_OUT := $(TARGET_INSTALLER_OUT)/root
250 TARGET_INSTALLER_SYSTEM_OUT := $(TARGET_INSTALLER_OUT)/root/system

上面的代码是指定了目标输出代码的位置和主机输出代码的位置,重要的几个如下:

PRODUCT_OUT = 这个的结果要根据product_config.mk文件内容来决定,其实是out/target/product/fs100/
TARGET_OUT = $(PRODUCT_OUT)/system
TARGET_OUT_EXECUTABLES = $(PRODUCT_OUT)/system/bin
TARGET_OUT_SHARED_LIBRARIES = $(PRODUCT_OUT)/system/lib
TARGET_OUT_JAVA_LIBRARIES = $(PRODUCT_OUT)/system/framework
TARGET_OUT_APPS = $(PRODUCT_OUT)/system/app
TARGET_OUT_ETC = $(PRODUCT_OUT)/system/etc
TARGET_OUT_STATIC_LIBRARIES = $(PRODUCT_OUT)/obj/lib
TARGET_OUT_DATA = $(PRODUCT_OUT)/data
TARGET_OUT_DATA_APPS = $(PRODUCT_OUT)/data/app
TARGET_ROOT_OUT = $(PRODUCT_OUT)/root
TARGET_ROOT_OUT_BIN = $(PRODUCT_OUT)/bin
TARGET_ROOT_OUT_SBIN = $(PRODUCT_OUT)/system/sbin
TARGET_ROOT_OUT_ETC = $(PRODUCT_OUT)/system/etc
TARGET_ROOT_OUT_USR = $(PRODUCT_OUT)/system/usr

总结下:

envsetup.mk文件主要包含了product_config.mk文件,然后指定了编译时要输出的所有文件的OUT目录。

4、 build/core/product_config.mk

157 include $(BUILD_SYSTEM)/product.mk
...
160 # Read in all of the product definitions specified by the AndroidProducts.mk
161 # files in the tree.
162 #
163 #TODO: when we start allowing direct pointers to product files,
164 # guarantee that they're in this list.
165 $(call import-products, $(get-all-product-makefiles))
166 $(check-all-products)
...
170 # Convert a short name like "sooner" into the path to the product
171 # file defining that product.
172 #
173 INTERNAL_PRODUCT := $(call resolve-short-product-name, $(TARGET_PRODUCT))
...
176 # Find the device that this product maps to.
177 TARGET_DEVICE := $(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_DEVICE)157行,我靠,又包含了product.mk文件

165行,调用函数import-products, $(get-all-product-makefiles),这儿我们看上面的注释:

Read in all of the product definitions specified by the AndroidProducts.mk files in the tree.
TODO: when we start allowing direct pointers to product files, guarantee that they're in this list.

意思是说:读取指定的目录下所有的AndrodProducts.mk文件中定义的产品信息

其实get-all-product-makefiles返回所有的产品文件xxx.mk

import-products函数去验证这些产品配置文件是否都包含有必须的配置信息,细节后面分析。

173行调用了resolve-short-product-name函数,它将返回TARGET_PRODUCT产品的配置文件目录,并赋给INTERNAL_PRODUCT

也就是说:

INTERNAL_PRODUCT = vendor/farsight/products/fs100.mk

TARGET_DEVICE = fs100

如果调试看其结果,可以在167行,将#$(dump-product)取消注释

然后在175行添加: $(info $(INTERNAL_PRODUCT))

在178行添加: $(info $(TARGET_DEVICE )),查看调试结果。

总结一下:

product_config.mk主要读取vendor目录下不同厂商自己定义的AndrodProducts.mk文件,从该文件里取得所有产品的配置文件,然后再根据lunch选择的编译项TARGET_PRODUCT,找到与之对应的配置文件,然后设置TARGET_DEVICE变量,用于后续编译。

5、 build/core/product.mk

17 #
18 # Functions for including AndroidProducts.mk files
19 #
20
21 #
22 # Returns the list of all AndroidProducts.mk files.
23 # $(call ) isn't necessary.
24 #
25 define <strong>_find-android-products-files</strong>
26 $(shell test -d vendor && find vendor -maxdepth 6 -name AndroidProducts.mk) \
27 $(SRC_TARGET_DIR)/product/AndroidProducts.mk
28 endef
29
30 #
31 # Returns the sorted concatenation of all PRODUCT_MAKEFILES
32 # variables set in all AndroidProducts.mk files.
33 # $(call ) isn't necessary.
34 #
35 define <strong>get-all-product-makefiles</strong>
36 $(sort \
37 $(foreach f,$(_find-android-products-files), \
38 $(eval PRODUCT_MAKEFILES :=) \
39 $(eval LOCAL_DIR := $(patsubst %/,%,$(dir $(f)))) \
40 $(eval include $(f)) \
41 $(PRODUCT_MAKEFILES) \
42 ) \
43 $(eval PRODUCT_MAKEFILES :=) \
44 $(eval LOCAL_DIR :=) \
45 )
46 endef通过注释可知,本文件中主要是一些用来处理AndroidProduct.mk的函数

_find-android-products-files:

用来获得vendor目录下,所有名字为AndroidProduct.mk的文件列表。

get-all-product-makefiles:

用来获得所有AndroidProduct.mk文件里定义的PRODUCT_MAKEFILES的值(其实是产品文件路径名)。

在vendor目录下,每个公司目录下都会存在一个AndroidProduct.mk文件,这个文件是用来定义这个公司的产品列表,每个产品用<product_name>.mk来表示, 如Android给的示例:

vendor/sample/products/AndroidProduct.mk。其内容如下:

1 #
2 # This file should set PRODUCT_MAKEFILES to a list of product makefiles
3 # to expose to the build system. LOCAL_DIR will already be set to
4 # the directory containing this file.
5 #
6 # This file may not rely on the value of any variable other than
7 # LOCAL_DIR; do not use any conditionals, and do not look up the
8 # value of any variable that isn't set in this file or in a file that
9 # it includes.
10 #
11
12 PRODUCT_MAKEFILES := \
13 $(LOCAL_DIR)/sample_addon.mk里面只定义了一个产品配置文件,即当前目录下的sample_addon.mk:
1 # List of apps and optional libraries (Java and native) to put in the add-on system image.
2 PRODUCT_PACKAGES := \
3 PlatformLibraryClient \
4 com.example.android.platform_library \
5 libplatform_library_jni

上述文件里定义了产品相关个性化信息,如,PRODUCT_PACKAGES表示要在当前产品里添加一些安装包。由此可见,get-all-product-makefiles函数,其实就是返回了当前公司里全部的产品对应的mk文件列表。

总结:

如果用户想个性定制自己的产品,应该有以下流程,包含上一节内容:

1. 创建公司目录

#mkdir vendor/farsight

2. 创建一个vendorsetup.sh文件,将当前产品编译项添加到lunch里,让lunch能找到用户个性定制编译项

#echo "add_lunch_combo fs100-eng" > vendor/farsight/vendorsetup.sh

3. 仿着Android示例代码,在公司目录下创建products目录

#mkdir -p vendor/farsight/products

4. 仿着Android示例代码,在products目录下创建两个mk文件

#touch vendor/farsight/products/AndroidProduct.mk vendor/farsight/products/fs100.mk

在AndroidProduct.mk里添加如下内容:

PRODUCT_MAKEFILES := $(LOCAL_DIR)/fs100.mk表示只有一个产品fs100,它对应的配置文件在当前目录下的fs100.mk。

5.在产品配置文件里添加最基本信息

1
2 PRODUCT_PACKAGES := \
3 IM \
4 VoiceDialer
5
6 $(call inherit-product, build/target/product/generic.mk) ##从某一默认配置开始派生余下内容参考派生起点
7
8 # Overrides
9 PRODUCT_MANUFACTURER := farsight
10 PRODUCT_NAME := fs100
11 PRODUCT_DEVICE := fs100

嵌入式及3G相关资源及学习请点击:嵌入式开发视频android开发视频android培训3G培训QT培训QT开发视频物联网培训物联网技术视频嵌入式学习

更多相关文章

  1. 基于Android扫描sd卡与系统文件的介绍
  2. Android窗口抖动之动画实现
  3. 详解Android中实现热更新的原理
  4. android mediarecord 实现暂停断点录音功能
  5. build android for VMware
  6. Android(安卓)studio 中创建AIDL Service
  7. (转)修改Android的开关机铃声、Android开关机画面与动画(附代码流程
  8. Android(九):adb常用命令
  9. NPM 和webpack 的基础使用

随机推荐

  1. android studio 取消自动保存功能(已解决)
  2. Android(安卓)加密解密
  3. android中动态布局(动态加入TextView和Li
  4. android网变化广播接收
  5. Android系统时间显示上下午
  6. android 弹出带输入框的对话框
  7. android 多点触摸实现图片缩放
  8. android 自动完成 AutoCompleteTextView
  9. LinearLayout 布局 底部固定导航
  10. Android(安卓)Studio 2.2 Preview - New