分别摘自:


Android编译过程详解(一):http://blog.csdn.net/mr_raptor/article/details/7539978

Android编译过程详解(二):http://blog.csdn.net/mr_raptor/article/details/7540066

Android编译过程详解(三):http://blog.csdn.net/mr_raptor/article/details/7540730

这三篇文章。

Android编译过程详解(一):http://blog.csdn.net/mr_raptor/article/details/7539978

Android的优势就在于其开源,手机和平板生产商可以根据自己的硬件进行个性定制自己的手机产品,如小米,LePhone,M9等,因此,在我们在对Android的源码进行定制的时候,很有必要了解下,Android的编译过程。

如果你从来没有做过Android代码的编译,那么最官方的编译过程就是查看Android的官方网站:http://source.android.com/source/building.html

但是,这儿只是告诉你了如何去编译一个通用的系统,并没有详细告诉你细节,我们跟着编译过程来了解下。

+--------------------------------------------------------------------------------------------------------------------+

本文使用Android版本为2.1,采用开发板为华清远见研发的FS_S5PC100 A8开发板。

+--------------------------------------------------------------------------------------------------------------------+

1. source build/envsetup.sh

这个命令是用来将envsetup.sh里的所有用到的命令加载到环境变量里去,我们来分析下它。

envsetup.sh里的主要命令如下:

[plain] view plain copy
  1. functionhelp()                 #显示帮助信息
  2. functionget_abs_build_var()           #获取绝对变量
  3. functionget_build_var()             #获取绝对变量
  4. functioncheck_product()             #检查product
  5. functioncheck_variant()             #检查变量
  6. functionsetpaths()               #设置文件路径
  7. functionprintconfig()              #打印配置
  8. functionset_stuff_for_environment()      #设置环境变量
  9. functionset_sequence_number()        #设置序号
  10. functionsettitle()               #设置标题
  11. functionchoosetype()              #设置type
  12. functionchooseproduct()            #设置product
  13. functionchoosevariant()            #设置variant
  14. functiontapas()                #功能同choosecombo
  15. functionchoosecombo()             #设置编译参数
  16. functionadd_lunch_combo()           #添加lunch项目
  17. functionprint_lunch_menu()           #打印lunch列表
  18. functionlunch()                 #配置lunch
  19. functionm()                   #makefromtop
  20. functionfindmakefile()             #查找makefile
  21. functionmm()                  #makefromcurrentdirectory
  22. functionmmm()                 #makethesupplieddirectories
  23. functioncroot()                 #回到根目录
  24. functioncproj()
  25. functionpid()
  26. functionsystemstack()
  27. functiongdbclient()
  28. functionjgrep()                 #查找java文件
  29. functioncgrep()                #查找c/cpp文件
  30. functionresgrep()
  31. functiontracedmdump()
  32. functionrunhat()
  33. functiongetbugreports()
  34. functionstartviewserver()
  35. functionstopviewserver()
  36. functionisviewserverstarted()
  37. functionsmoketest()
  38. functionruntest()
  39. functiongodir()                #跳到指定目录
  40. #这是系统自动增加了一个默认的编译项generic-eng
  41. #addthedefaultonehere
  42. add_lunch_combogeneric-eng
  43. #下面的代码很重要,它要从vendor目录下查找vendorsetup.sh文件,如果查到了,就加载它
  44. #Executethecontentsofanyvendorsetup.shfileswecanfind.
  45. forfin`/bin/lsvendor/*/vendorsetup.shvendor/*/build/vendorsetup.sh2>/dev/null`
  46. do
  47. echo"including$f"
  48. .$f
  49. done
根据上面的内容,可以推测出,如果要想定义自己的产品编译项,简单的办法是直接在envsetup.sh最后,添加上add_lunch_combo myProduct-eng,当然这么做,不太符合上面代码最后的本意,我们还是老实的在vendor目录下创建自己公司名字,然后在公司目录下创建一个新的vendorsetup.sh,在里面添加上自己的产 品编译项

[plain] view plain copy
  1. #mkdirvendor/farsight/
  2. #touchvendor/farsight/vendorsetup.sh
  3. #echo"add_lunch_combofs100-eng">vendor/farsight/vendorsetup.sh
这样,当我们在执行source build/envsetup.sh命令的时候,可以在shell上看到下面的信息:

[plain] view plain copy
  1. includingvendor/farsight/vendorsetup.sh

2. 按照android官网的步骤,开始执行lunch full-eng

当然如果你按上述命令执行,它编译的还是通用的eng版本系统,不是我们个性系统,我们可以执行lunch命令,它会打印出一个选择菜单,列出可用的编译选项

如果你按照第一步中添加了vendorsetup.sh那么,你的选项中会出现:

[plain] view plain copy
  1. You'rebuildingonLinux
  2. generic-engsimulatorfs100-eng
  3. Lunchmenu...pickacombo:
  4. 1.generic-eng
  5. 2.simulator
  6. 3.fs100-eng
其中第3项是我们自己添加的编译项。

lunch命令是envsetup.sh里定义的一个命令,用来让用户选择编译项,来定义Product和编译过程中用到的全局变量。

我们一直没有说明前面的fs100-eng是什么意思,现在来说明下,fs100是我定义的产品的名字,eng是产品的编译类型,除了eng外,还有user, userdebug,分别表示:

eng: 工程机,

user:最终用户机

userdebug:调试测试机

由此可见,除了eng和user外,另外两个一般不能交给最终用户的,记得m8出来的时候,先放出了一部分eng工程机,然后出来了user机之后,可以用工程机换。

好了,我们来分析下lunch命令干了什么?

[plain] view plain copy
  1. functionlunch()
  2. {
  3. localanswer
  4. if["$1"];then
  5. #lunch后面直接带参数
  6. answer=$1
  7. else
  8. #lunch后面不带参数,则打印处所有的targetproduct和variant菜单提供用户选择
  9. print_lunch_menu
  10. echo-n"Whichwouldyoulike?[generic-eng]"
  11. readanswer
  12. fi
  13. localselection=
  14. if[-z"$answer"]
  15. then
  16. #如果用户在菜单中没有选择,直接回车,则为系统缺省的generic-eng
  17. selection=generic-eng
  18. elif["$answer"="simulator"]
  19. then
  20. #如果是模拟器
  21. selection=simulator
  22. elif(echo-n$answer|grep-q-e"^[0-9][0-9]*$")
  23. then
  24. #如果answer是选择菜单的数字,则获取该数字对应的字符串
  25. if[$answer-le${#LUNCH_MENU_CHOICES[@]}]
  26. then
  27. selection=${LUNCH_MENU_CHOICES[$(($answer-$_arrayoffset))]}
  28. fi
  29. #如果answer字符串匹配*-*模式(*的开头不能为-)
  30. elif(echo-n$answer|grep-q-e"^[^\-][^\-]*-[^\-][^\-]*$")
  31. then
  32. selection=$answer
  33. fi
  34. if[-z"$selection"]
  35. then
  36. echo
  37. echo"Invalidlunchcombo:$answer"
  38. return1
  39. fi
  40. #specialcasethesimulator
  41. if["$selection"="simulator"]
  42. then
  43. #模拟器模式
  44. exportTARGET_PRODUCT=sim
  45. exportTARGET_BUILD_VARIANT=eng
  46. exportTARGET_SIMULATOR=true
  47. exportTARGET_BUILD_TYPE=debug
  48. else
  49. #将product-variant模式种的product分离出来
  50. localproduct=$(echo-n$selection|sed-e"s/-.*$//")
  51. #检查之,调用关系check_product()->get_build_var()->build/core/config.mk比较罗嗦,不展开了
  52. check_product$product
  53. if[$?-ne0]
  54. then
  55. echo
  56. echo"**Don'thaveaproductspecfor:'$product'"
  57. echo"**Doyouhavetherightrepomanifest?"
  58. product=
  59. fi
  60. #将product-variant模式种的variant分离出来
  61. localvariant=$(echo-n$selection|sed-e"s/^[^\-]*-//")
  62. #检查之,看看是否在(useruserdebugeng)范围内
  63. check_variant$variant
  64. if[$?-ne0]
  65. then
  66. echo
  67. echo"**Invalidvariant:'$variant'"
  68. echo"**Mustbeoneof${VARIANT_CHOICES[@]}"
  69. variant=
  70. fi
  71. if[-z"$product"-o-z"$variant"]
  72. then
  73. echo
  74. return1
  75. fi
  76. <spanstyle="WHITE-SPACE:pre"></span>#导出环境变量,这儿很重要,因为后面的编译系统都是依赖于这里定义的几个变量的
  77. exportTARGET_PRODUCT=$product
  78. exportTARGET_BUILD_VARIANT=$variant
  79. exportTARGET_SIMULATOR=false
  80. exportTARGET_BUILD_TYPE=release
  81. fi#!simulator
  82. echo
  83. #设置到环境变量,比较多,不再一一列出,最简单的方法set>env.txt可获得
  84. set_stuff_for_environment
  85. #打印一些主要的变量,调用关系printconfig()->get_build_var()->build/core/config.mk->build/core/envsetup.mk比较罗嗦,不展开了
  86. printconfig
  87. }
由上面分析可知,lunch命令可以带参数和不带参数,最终导出一些重要的环境变量,从而影响编译系统的编译结果。导出的变量如下(以实际运行情况为例)

[plain] view plain copy
  1. TARGET_PRODUCT=fs100
  2. TARGET_BUILD_VARIANT=eng
  3. TARGET_SIMULATOR=false
  4. TARGET_BUILD_TYPE=release

执行完上述两个步骤,就该执行:make命令了,下篇来分析。




Android编译过程详解(二):http://blog.csdn.net/mr_raptor/article/details/7540066

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


1. make

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

[html] view plain copy
  1. 1###DONOTEDITTHISFILE###
  2. 2includebuild/core/main.mk
  3. 3###DONOTEDITTHISFILE###

呵呵,看到上面 的内容,我们都会笑,这是我见过最简单的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包含。

定义了以下环境变量:

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

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

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

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

[plain] view plain copy
  1. 109#---------------------------------------------------------------
  2. 110#Definemostoftheglobalvariables.Thesearetheonesthat
  3. 111#arespecifictotheuser'sbuildconfiguration.
  4. 112include$(BUILD_SYSTEM)/envsetup.mk
  5. 113
  6. 114#Boardsmaybedefinedunder$(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)
  7. 115#orundervendor/*/$(TARGET_DEVICE).Searchinbothplaces,but
  8. 116#makesureonlyoneexists.
  9. 117#RealboardsshouldalwaysbeassociatedwithanOEMvendor.
  10. 118board_config_mk:=\
  11. 119$(strip$(wildcard\
  12. 120$(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)/BoardConfig.mk\
  13. 121vendor/*/$(TARGET_DEVICE)/BoardConfig.mk\
  14. 122))
  15. 123ifeq($(board_config_mk),)
  16. 124$(errorNoconfigfilefoundforTARGET_DEVICE$(TARGET_DEVICE))
  17. 125endif
  18. 126ifneq($(words$(board_config_mk)),1)
  19. 127$(errorMultipleboardconfigfilesforTARGET_DEVICE$(TARGET_DEVICE):$(board_config_mk))
  20. 128endif
  21. 129include$(board_config_mk)
  22. 130TARGET_DEVICE_DIR:=$(patsubst%/,%,$(dir$(board_config_mk)))
  23. 131board_config_mk:=
112行又包含了另外一个重要的mk文件envsetup.mk,我们来看一下。


3. envsetup.mk

[plain] view plain copy
  1. 25ifeq($(TARGET_PRODUCT),)#判断TARGET_PRODUCT是否为空,
  2. 26ifeq($(TARGET_SIMULATOR),true)
  3. 27TARGET_PRODUCT:=sim
  4. 28else
  5. 29TARGET_PRODUCT:=generic
  6. 30endif
  7. 31endif
第25行,判断 TARGET_PRODUCT是否为空, 根据上一节分析可知, TARGET_PRODUCT=fs100
[plain] view plain copy
  1. 34#thevariant--thesetoffilesthatareincludedforabuild
  2. 35ifeq($(strip$(TARGET_BUILD_VARIANT)),)
  3. 36TARGET_BUILD_VARIANT:=eng
  4. 37endif
  5. 38
  6. 39#ReadtheproductspecssoweangetTARGET_DEVICEandother
  7. 40#variablesthatweneedinordertolocatetheoutputfiles.
  8. 41include$(BUILD_SYSTEM)/product_config.mk
在41行又包含了 product_config.mk 文件,等会我们再分析它,先看下面的

[plain] view plain copy
  1. 148#---------------------------------------------------------------
  2. 149#figureouttheoutputdirectories
  3. 150
  4. 151ifeq(,$(strip$(OUT_DIR)))
  5. 152OUT_DIR:=$(TOPDIR)out
  6. 153endif
  7. 154
  8. 155DEBUG_OUT_DIR:=$(OUT_DIR)/debug
  9. 156
  10. 157#Movethehostortargetunderthedebug/directory
  11. 158#ifnecessary.
  12. 159TARGET_OUT_ROOT_release:=$(OUT_DIR)/target
  13. 160TARGET_OUT_ROOT_debug:=$(DEBUG_OUT_DIR)/target
  14. 161TARGET_OUT_ROOT:=$(TARGET_OUT_ROOT_$(TARGET_BUILD_TYPE))
  15. 162
  16. ...
  17. 184PRODUCT_OUT:=$(TARGET_PRODUCT_OUT_ROOT)/$(TARGET_DEVICE)
  18. 187
  19. 188HOST_OUT_EXECUTABLES:=$(HOST_OUT)/bin
  20. 189HOST_OUT_SHARED_LIBRARIES:=$(HOST_OUT)/lib
  21. 190HOST_OUT_JAVA_LIBRARIES:=$(HOST_OUT)/framework
  22. 191HOST_OUT_SDK_ADDON:=$(HOST_OUT)/sdk_addon
  23. ...
  24. 200TARGET_OUT_INTERMEDIATES:=$(PRODUCT_OUT)/obj
  25. 201TARGET_OUT_HEADERS:=$(TARGET_OUT_INTERMEDIATES)/include
  26. 202TARGET_OUT_INTERMEDIATE_LIBRARIES:=$(TARGET_OUT_INTERMEDIATES)/lib
  27. 203TARGET_OUT_COMMON_INTERMEDIATES:=$(TARGET_COMMON_OUT_ROOT)/obj
  28. 204
  29. 205TARGET_OUT:=$(PRODUCT_OUT)/system
  30. 206TARGET_OUT_EXECUTABLES:=$(TARGET_OUT)/bin
  31. 207TARGET_OUT_OPTIONAL_EXECUTABLES:=$(TARGET_OUT)/xbin
  32. 208TARGET_OUT_SHARED_LIBRARIES:=$(TARGET_OUT)/lib
  33. 209TARGET_OUT_JAVA_LIBRARIES:=$(TARGET_OUT)/framework
  34. 210TARGET_OUT_APPS:=$(TARGET_OUT)/app
  35. 211TARGET_OUT_KEYLAYOUT:=$(TARGET_OUT)/usr/keylayout
  36. 212TARGET_OUT_KEYCHARS:=$(TARGET_OUT)/usr/keychars
  37. 213TARGET_OUT_ETC:=$(TARGET_OUT)/etc
  38. 214TARGET_OUT_STATIC_LIBRARIES:=$(TARGET_OUT_INTERMEDIATES)/lib
  39. 215TARGET_OUT_NOTICE_FILES:=$(TARGET_OUT_INTERMEDIATES)/NOTICE_FILES
  40. 216
  41. 217TARGET_OUT_DATA:=$(PRODUCT_OUT)/data
  42. 218TARGET_OUT_DATA_EXECUTABLES:=$(TARGET_OUT_EXECUTABLES)
  43. 219TARGET_OUT_DATA_SHARED_LIBRARIES:=$(TARGET_OUT_SHARED_LIBRARIES)
  44. 220TARGET_OUT_DATA_JAVA_LIBRARIES:=$(TARGET_OUT_JAVA_LIBRARIES)
  45. 221TARGET_OUT_DATA_APPS:=$(TARGET_OUT_DATA)/app
  46. 222TARGET_OUT_DATA_KEYLAYOUT:=$(TARGET_OUT_KEYLAYOUT)
  47. 223TARGET_OUT_DATA_KEYCHARS:=$(TARGET_OUT_KEYCHARS)
  48. 224TARGET_OUT_DATA_ETC:=$(TARGET_OUT_ETC)
  49. 225TARGET_OUT_DATA_STATIC_LIBRARIES:=$(TARGET_OUT_STATIC_LIBRARIES)
  50. 226
  51. 227TARGET_OUT_UNSTRIPPED:=$(PRODUCT_OUT)/symbols
  52. 228TARGET_OUT_EXECUTABLES_UNSTRIPPED:=$(TARGET_OUT_UNSTRIPPED)/system/bin
  53. 229TARGET_OUT_SHARED_LIBRARIES_UNSTRIPPED:=$(TARGET_OUT_UNSTRIPPED)/system/lib
  54. 230TARGET_ROOT_OUT_UNSTRIPPED:=$(TARGET_OUT_UNSTRIPPED)
  55. 231TARGET_ROOT_OUT_SBIN_UNSTRIPPED:=$(TARGET_OUT_UNSTRIPPED)/sbin
  56. 232TARGET_ROOT_OUT_BIN_UNSTRIPPED:=$(TARGET_OUT_UNSTRIPPED)/bin
  57. 233
  58. 234TARGET_ROOT_OUT:=$(PRODUCT_OUT)/root
  59. 235TARGET_ROOT_OUT_BIN:=$(TARGET_ROOT_OUT)/bin
  60. 236TARGET_ROOT_OUT_SBIN:=$(TARGET_ROOT_OUT)/sbin
  61. 237TARGET_ROOT_OUT_ETC:=$(TARGET_ROOT_OUT)/etc
  62. 238TARGET_ROOT_OUT_USR:=$(TARGET_ROOT_OUT)/usr
  63. 239
  64. 240TARGET_RECOVERY_OUT:=$(PRODUCT_OUT)/recovery
  65. 241TARGET_RECOVERY_ROOT_OUT:=$(TARGET_RECOVERY_OUT)/root
  66. 242
  67. 243TARGET_SYSLOADER_OUT:=$(PRODUCT_OUT)/sysloader
  68. 244TARGET_SYSLOADER_ROOT_OUT:=$(TARGET_SYSLOADER_OUT)/root
  69. 245TARGET_SYSLOADER_SYSTEM_OUT:=$(TARGET_SYSLOADER_OUT)/root/system
  70. 246
  71. 247TARGET_INSTALLER_OUT:=$(PRODUCT_OUT)/installer
  72. 248TARGET_INSTALLER_DATA_OUT:=$(TARGET_INSTALLER_OUT)/data
  73. 249TARGET_INSTALLER_ROOT_OUT:=$(TARGET_INSTALLER_OUT)/root
  74. 250TARGET_INSTALLER_SYSTEM_OUT:=$(TARGET_INSTALLER_OUT)/root/system
上面的代码是指定了目标输出代码的位置和主机输出代码的位置,重要的几个如下:

[plain] view plain copy
  1. PRODUCT_OUT=这个的结果要根据product_config.mk文件内容来决定,其实是out/target/product/fs100/
  2. TARGET_OUT=$(PRODUCT_OUT)/system
  3. TARGET_OUT_EXECUTABLES=$(PRODUCT_OUT)/system/bin
  4. TARGET_OUT_SHARED_LIBRARIES=$(PRODUCT_OUT)/system/lib
  5. TARGET_OUT_JAVA_LIBRARIES=$(PRODUCT_OUT)/system/framework
  6. TARGET_OUT_APPS=$(PRODUCT_OUT)/system/app
  7. TARGET_OUT_ETC=$(PRODUCT_OUT)/system/etc
  8. TARGET_OUT_STATIC_LIBRARIES=$(PRODUCT_OUT)/obj/lib
  9. TARGET_OUT_DATA=$(PRODUCT_OUT)/data
  10. TARGET_OUT_DATA_APPS=$(PRODUCT_OUT)/data/app
  11. TARGET_ROOT_OUT=$(PRODUCT_OUT)/root
  12. TARGET_ROOT_OUT_BIN=$(PRODUCT_OUT)/bin
  13. TARGET_ROOT_OUT_SBIN=$(PRODUCT_OUT)/system/sbin
  14. TARGET_ROOT_OUT_ETC=$(PRODUCT_OUT)/system/etc
  15. TARGET_ROOT_OUT_USR=$(PRODUCT_OUT)/system/usr

总结下:

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


4. build/core/product_config.mk

[plain] view plain copy
  1. 157include$(BUILD_SYSTEM)/product.mk
  2. ...
  3. 160#ReadinalloftheproductdefinitionsspecifiedbytheAndroidProducts.mk
  4. 161#filesinthetree.
  5. 162#
  6. 163#TODO:whenwestartallowingdirectpointerstoproductfiles,
  7. 164#guaranteethatthey'reinthislist.
  8. 165$(callimport-products,$(get-all-product-makefiles))
  9. 166$(check-all-products)
  10. ...
  11. 170#Convertashortnamelike"sooner"intothepathtotheproduct
  12. 171#filedefiningthatproduct.
  13. 172#
  14. 173INTERNAL_PRODUCT:=$(callresolve-short-product-name,$(TARGET_PRODUCT))
  15. ...
  16. 176#Findthedevicethatthisproductmapsto.
  17. 177TARGET_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.mkfiles 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

[plain] view plain copy
  1. 17#
  2. 18#FunctionsforincludingAndroidProducts.mkfiles
  3. 19#
  4. 20
  5. 21#
  6. 22#ReturnsthelistofallAndroidProducts.mkfiles.
  7. 23#$(call)isn'tnecessary.
  8. 24#
  9. 25define<strong>_find-android-products-files</strong>
  10. 26$(shelltest-dvendor&&findvendor-maxdepth6-nameAndroidProducts.mk)\
  11. 27$(SRC_TARGET_DIR)/product/AndroidProducts.mk
  12. 28endef
  13. 29
  14. 30#
  15. 31#ReturnsthesortedconcatenationofallPRODUCT_MAKEFILES
  16. 32#variablessetinallAndroidProducts.mkfiles.
  17. 33#$(call)isn'tnecessary.
  18. 34#
  19. 35define<strong>get-all-product-makefiles</strong>
  20. 36$(sort\
  21. 37$(foreachf,$(_find-android-products-files),\
  22. 38$(evalPRODUCT_MAKEFILES:=)\
  23. 39$(evalLOCAL_DIR:=$(patsubst%/,%,$(dir$(f))))\
  24. 40$(evalinclude$(f))\
  25. 41$(PRODUCT_MAKEFILES)\
  26. 42)\
  27. 43$(evalPRODUCT_MAKEFILES:=)\
  28. 44$(evalLOCAL_DIR:=)\
  29. 45)
  30. 46endef
通过注释可知,本文件中主要是一些用来处理AndroidProduct.mk的函数
_find-android-products-files:

用来获得vendor目录下,所有名字为AndroidProduct.mk的文件列表。
get-all-product-makefiles:

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


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

[plain] view plain copy
  1. vendor/sample/products/AndroidProduct.mk
其内容如下:

[plain] view plain copy
  1. 1#
  2. 2#ThisfileshouldsetPRODUCT_MAKEFILEStoalistofproductmakefiles
  3. 3#toexposetothebuildsystem.LOCAL_DIRwillalreadybesetto
  4. 4#thedirectorycontainingthisfile.
  5. 5#
  6. 6#Thisfilemaynotrelyonthevalueofanyvariableotherthan
  7. 7#LOCAL_DIR;donotuseanyconditionals,anddonotlookupthe
  8. 8#valueofanyvariablethatisn'tsetinthisfileorinafilethat
  9. 9#itincludes.
  10. 10#
  11. 11
  12. 12PRODUCT_MAKEFILES:=\
  13. 13$(LOCAL_DIR)/sample_addon.mk
里面只定义了一个产品配置文件,即当前目录下的sample_addon.mk:
[plain] view plain copy
  1. 1#Listofappsandoptionallibraries(Javaandnative)toputintheadd-onsystemimage.
  2. 2PRODUCT_PACKAGES:=\
  3. 3PlatformLibraryClient\
  4. 4com.example.android.platform_library\
  5. 5libplatform_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里添加如下内容:

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

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

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

Android编译过程详解(三):http://blog.csdn.net/mr_raptor/article/details/7540730

前面两节讲解了自定义Android编译项和创建Product产品配置文件,除了编译和定义产品相关环境变量外,还需要定义Board相关环境变量。

1.build/core/config.mk

[plain] view plain copy
  1. <prename="code"class="plain">109#---------------------------------------------------------------
  2. 110#Definemostoftheglobalvariables.Thesearetheonesthat
  3. 111#arespecifictotheuser'sbuildconfiguration.
  4. 112include$(BUILD_SYSTEM)/envsetup.mk
  5. 113
  6. 114#Boardsmaybedefinedunder$(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)
  7. 115#orundervendor/*/$(TARGET_DEVICE).Searchinbothplaces,but
  8. 116#makesureonlyoneexists.
  9. 117#RealboardsshouldalwaysbeassociatedwithanOEMvendor.
  10. 118board_config_mk:=\
  11. 119$(strip$(wildcard\
  12. 120$(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)/BoardConfig.mk\
  13. 121vendor/*/$(TARGET_DEVICE)/BoardConfig.mk\
  14. 122))
  15. 123ifeq($(board_config_mk),)
  16. 124$(errorNoconfigfilefoundforTARGET_DEVICE$(TARGET_DEVICE))
  17. 125endif
  18. 126ifneq($(words$(board_config_mk)),1)
  19. 127$(errorMultipleboardconfigfilesforTARGET_DEVICE$(TARGET_DEVICE):$(board_config_mk))
  20. 128endif
  21. 129include$(board_config_mk)
  22. 130TARGET_DEVICE_DIR:=$(patsubst%/,%,$(dir$(board_config_mk)))
  23. 131board_config_mk:=
  

  上述代码在上一节已经见到过,只是分析了112行的envsetup.mk,根据上一节内容可知,  envsetup.mk设置了很多OUT变量,最终在build/core/product_config.mk文件里,设置了TARGET_DEVICE = fs100。  

我们从114行继续分析。

从114~117行解释大意可知:

Board相关配置文件会存在于$(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)/或vendor/*/$(TARGET_DEVICE)/目录中,一个Vendor厂商只能有一个对应的Board配置文件。

118行定义board_config_mk变量:

$(wildcard xxx)函数就是找到与xxx的匹配项放到空格列表里,前面定义TARGET_DEVICE变量 =fs100,所以$(SRC_TARGET_DIR)/board/fs100/BoardConfig.mk不存在,必须要存在vendor/*/fs100/BoardConfig.mk文件来定义开发板配置信息

129行,通过include将vendor/*/fs100/BoardConfig.mk包含进来,

130行,TARGET_DEVICE_DIR为board_config_mk的路径,即:vendor/*/fs100

总结:

一个vendor厂商必须要有一个对应的Board配置文件,即:vendor/*/fs100/BoardConfig.mk

定义了TARGET_DEVICE_DIR变量,为board_config_mk的路径,即:vendor/*/fs100

指定board 相关特性,一定要包含:
TARGET_CPU_ABI := armeabi/...
其他属性参见其他board样例.(build/target/board/XXX

2.build/core/main.mk

[plain] view plain copy
  1. 141#Bringinstandardbuildsystemdefinitions.
  2. 142include$(BUILD_SYSTEM)/definitions.mk
  3. ...
  4. 347ifeq($(SDK_ONLY),true)
  5. 348
  6. 349#-----SDKforWindows------
  7. 350#TheseconfigurethebuildtargetsthatareavailablefortheSDKunderCygwin.
  8. 351#ThefirstsectiondefinesalltheC/C++toolsthatcanbecompiledunderCygwin,
  9. 352#thesecondsectiondefinesalltheJavaones(assumingjavacisavailable.)
  10. 353
  11. 354subdirs:=\
  12. 355prebuilt\
  13. 356build/libs/host\
  14. 357build/tools/zipalign\
  15. ...
  16. 382#Thefollowingcanonlybebuiltif"javac"isavailable.
  17. 383#ThischeckisusedwhenbuildingpartsoftheSDKunderCygwin.
  18. 384ifneq(,$(shellwhichjavac2>/dev/null))
  19. 385$(warningsdk-only:javacavailable.)
  20. 386subdirs+=\
  21. 387build/tools/signapk\
  22. 388dalvik/dx\
  23. 389dalvik/libcore\
  24. ...
  25. 414else#!SDK_ONLY
  26. 415ifeq($(BUILD_TINY_ANDROID),true)
  27. 416
  28. 417#TINY_ANDROIDisasuper-minimalbuildconfiguration,handyforboard
  29. 418#bringupandverylowleveldebugging
  30. 419
  31. 420subdirs:=\
  32. 421bionic\
  33. 422system/core\
  34. 423build/libs\
  35. 424build/target\
  36. ...
  37. 433else#!BUILD_TINY_ANDROID
  38. 434
  39. 435#
  40. 436#Typicalbuild;includeanyAndroid.mkfileswecanfind.
  41. 437#
  42. 438subdirs:=$(TOP)
  43. 439
  44. 440FULL_BUILD:=true
  45. 441
  46. 442endif#!BUILD_TINY_ANDROID
  47. 443
  48. 444endif#!SDK_ONLY
  49. ...
  50. 464#
  51. 465#Includeallofthemakefilesinthesystem
  52. 466#
  53. 467
  54. 468#Can'tusefirst-makefiles-underherebecause
  55. 469#--mindepth=2makestheprunesnotwork.
  56. 470subdir_makefiles:=\
  57. 471$(shellbuild/tools/findleaves.py--prune=out--prune=.repo--prune=.git$(subdirs)Android.mk)
  58. 472
  59. 473include$(subdir_makefiles)

上一节只是讲了main.mk第49行中包含了config.mk,我们继续分析。

142行包含了:build/core/definitions.mk,该文件定义了很多全局变量与函数。

如下列常见函数:

my-dir:返回当前路径

all-java-files-under:获得指定目录及子目录一所有java文件

all-subdir-c-files:获得当前目录下及子目录下所有c文件

354~444行,定义了subdirs变量,依据不同的用户编译条件,而包含Android源码中不同的目录。

470行,定义了subdir_makefile变量,其值为subdirs定义的目录中的Android.mk文件。

473行,将所有编译目录中的Android.mk文件包含进来。

3. build/target/board/Android.mk

[plain] view plain copy
  1. 26ifeq(,$(wildcard$(TARGET_DEVICE_DIR)/AndroidBoard.mk))
  2. 27ifeq(,$(wildcard$(TARGET_DEVICE_DIR)/Android.mk))
  3. 28$(errorMissing"$(TARGET_DEVICE_DIR)/AndroidBoard.mk")
  4. 29else
  5. 30#TODO:Removethischeckafterpeoplehavehadachancetoswitch,
  6. 31#afterApril2009.
  7. 32$(errorPleaserename"$(TARGET_DEVICE_DIR)/Android.mk"to"$(TARGET_DEVICE_DIR)/AndroidBoard.mk")
  8. 33endif
  9. 34endif
  10. 35include$(TARGET_DEVICE_DIR)/AndroidBoard.mk
由于将所有目录中Android.mk文件include进来,build/target/board/Android.mk自然被包含进来,根据前面分析,TARGET_DEVICE_DIR = vendor/*/ fs100, 其中26~35行用来判断对应的产品目录下是否存在AndrodiBoard.mk,如果不存在,提示出错退出,如果存在,将其包含到编译脚本中。

由此可见:我们必须要在产品目录下创建AndrodiBoard.mk文件,来描述开发板相关配置项,我们可以借鉴:build/target/board/generic/AndroidBoard.mk内容,同时根据前面所分析,还要创建BoardConfig.mk文件。

[plain] view plain copy
  1. #cpbuild/target/board/generic/AndroidBoard.mkbuild/target/board/generic/BoardConfig.mkvendor/farsight/fs100/
至此,自定义Android编译选项基本步骤已经分部分析完,细节还需要针对不同开发板具体分析。

总结:

build/core/main.mk包含了config.mk,它主要定义了编译全部代码的依赖关系

build/core/config.mk 定义了大量的编译脚本命令,编译时用到的环境变量,引入了envsetup.mk 文件,加载board相关配置文件。
build/core/envsetup.mk 定义了编译时用到的大量OUT输出目录,加载product_config.mk文件
build/core/product_config.mk 定义了Vendor目录下Product相关配置文件解析脚本,读取AndrodProducts.mk生成TARGET_DEVICE变量
build/target/product product config
build/target/board board config
build/core/combo build flags config

这里解释下这里的board和product。borad主要是设计到硬件芯片的配置,比如是否提供硬件的某些功能,比如说GPU等等,或者芯片支持浮 点运算等等。product是指针对当前的芯片配置定义你将要生产产品的个性配置,主要是指APK方面的配置,哪些APK会包含在哪个product中, 哪些APK在当前product中是不提供的。
config.mk是一个总括性的东西,它里面定义了各种module编译所需要使用的HOST工具以及如何来编译各种模块,比如说 BUILT_PREBUILT就定义了如何来编译预编译模块。envsetup.mk主要会读取由envsetup.sh写入环境变量中的一些变量来配置编译过程中的输出目录,combo里面主要定义了各种Host和Target结合的编译器和编译选项。

1. 在vendor目录下创建自己公司目录,然后在公司目录下创建一个新的vendorsetup.sh,在里面添加上自己的产品编译项

[plain] view plain copy
  1. #mkdirvendor/farsight/
  2. #touchvendor/farsight/vendorsetup.sh
  3. #echo"add_lunch_combofs100-eng">vendor/farsight/vendorsetup.sh
2. 仿着Android示例代码,在公司目录下创建products目录

[plain] view plain copy
  1. #mkdir-pvendor/farsight/products
3. 仿着Android示例代码,在products目录下创建两个mk文件

[plain] view plain copy
  1. #touchvendor/farsight/products/AndroidProduct.mkvendor/farsight/products/fs100.mk
在AndroidProduct.mk里添加如下内容:
[sql] view plain copy
  1. PRODUCT_MAKEFILES:=$(LOCAL_DIR)/fs100.mk
在产品配置文件里添加最基本信息

[plain] view plain copy
  1. PRODUCT_PACKAGES:=\
  2. IM\
  3. VoiceDialer
  4. $(callinherit-product,build/target/product/generic.mk)
  5. #Overrides
  6. PRODUCT_MANUFACTURER:=farsight
  7. PRODUCT_NAME:=fs100
  8. PRODUCT_DEVICE:=fs100
4. 借鉴build/target/board/generic/AndroidBoard.mk和BoardConfig.mk,创建对应文件。

[plain] view plain copy
  1. #cpbuild/target/board/generic/AndroidBoard.mkbuild/target/board/generic/BoardConfig.mkvendor/farsight/fs100/



更多相关文章

  1. Android 下载文件及写入SD卡
  2. 高焕堂android中文书全,电子文件for version 1.0
  3. Android:关于声明文件中android:process属性说明
  4. 2.5.3 使用alertDialog创建自定义对话框
  5. android编译时添加库第三方库文件
  6. AndroidManifest.xml文件详解

随机推荐

  1. Android(安卓)App程序结构
  2. Android网络开发详解
  3. android 程序检查当前应用是否在运行
  4. Android(安卓)WebView 禁止输入
  5. android日志工具LogCat的使用
  6. android下如何设置系统时间
  7. Android(安卓)系统设置默认launcher
  8. Android Studio 插件(一)
  9. 处理控制器输入动作
  10. android opengl es 飘落的星星