Android编译过程详解(一)

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

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 plaincopyprint?
                1. function help()                  # 显示帮助信息
                2. function get_abs_build_var()           # 获取绝对变量
                3. function get_build_var()             # 获取绝对变量
                4. function check_product()             # 检查product
                5. function check_variant()             # 检查变量
                6. function setpaths()                # 设置文件路径
                7. function printconfig()              # 打印配置
                8. function set_stuff_for_environment()       # 设置环境变量
                9. function set_sequence_number()         # 设置序号
                10. function settitle()                # 设置标题
                11. function choosetype()               # 设置type
                12. function chooseproduct()             # 设置product
                13. function choosevariant()             # 设置variant
                14. function tapas()                 # 功能同choosecombo
                15. function choosecombo()              # 设置编译参数
                16. function add_lunch_combo()            # 添加lunch项目
                17. function print_lunch_menu()            # 打印lunch列表
                18. function lunch()                 # 配置lunch
                19. function m()                   # make from top
                20. function findmakefile()              # 查找makefile
                21. function mm()                   # make from current directory
                22. function mmm()                  # make the supplied directories
                23. function croot()                 # 回到根目录
                24. function cproj()
                25. function pid()
                26. function systemstack()
                27. function gdbclient()
                28. function jgrep()                 # 查找java文件
                29. function cgrep()                 # 查找c/cpp文件
                30. function resgrep()
                31. function tracedmdump()
                32. function runhat()
                33. function getbugreports()
                34. function startviewserver()
                35. function stopviewserver()
                36. function isviewserverstarted()
                37. function smoketest()
                38. function runtest()
                39. function godir ()                 # 跳到指定目录
                40.
                41.
                42. # 这是系统自动增加了一个默认的编译项 generic-eng
                43. # add the default one here
                 44. <strong><span style="color:#ff0000;">add_lunch_combo generic-eng</span></strong>
                45.
                46.
                47. # 下面的代码很重要,它要从vendor目录下查找vendorsetup.sh文件,如果查到了,就加载它
                48. # Execute the contents of any vendorsetup.sh files we can find.
                49. <strong><span style="color:#ff0000;">for f in `/bin/ls vendor/*/vendorsetup.sh vendor/*/build/vendorsetup.sh 2> /dev/null`
                50. do
                51. echo "including $f"
                52. . $f
                53. done</span></strong>

根据上面的内容,可以推测出,如果要想定义自己的产品编译项,简单的办法是直接在envsetup.sh最后,添加上add_lunch_combo myProduct-eng,当然这么做,不太符合上面代码最后的本意,我们还是老实的在vendor目录下创建自己公司名字,然后在公司目录下创建一个新的vendorsetup.sh,在里面添加上自己的产品编译项。

[plain] view plaincopyprint?
                1. #mkdir vendor/farsight/
                2. #touch vendor/farsight/vendorsetup.sh
                3. #echo "add_lunch_combo fs100-eng" > vendor/farsight/vendorsetup.sh

这样,当我们在执行source build/envsetup.sh命令的时候,可以在shell上看到下面的信息:

[plain] view plaincopyprint?
                1. including vendor/farsight/vendorsetup.sh
                2. 按照android官网的步骤,开始执行lunch full-eng

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

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

[plain] view plaincopyprint?
                1. You're building on Linux
                2.
                3. generic-eng simulator fs100-eng
                4. Lunch menu... pick a combo:
                5. generic-eng
                6. simulator
                7. 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 plaincopyprint?
                1. function lunch()
                2. {
                3. local answer
                4.
                5. if [ "$1" ] ; then
                6. # lunch后面直接带参数
                7. answer=$1
                8. else
                9. # lunch后面不带参数,则打印处所有的target product和variant菜单提供用户选择
                10. print_lunch_menu
                11. echo -n "Which would you like? [generic-eng] "
                12. read answer
                13. fi
                14.
                15. local selection=
                16.
                17. if [ -z "$answer" ]
                18. then
                19. # 如果用户在菜单中没有选择,直接回车,则为系统缺省的generic-eng
                20. selection=generic-eng
                21. elif [ "$answer" = "simulator" ]
                22. then
                 23. # 如果是模拟器
                 24. selection=simulator
                 25. elif (echo -n $answer | grep -q -e "^[0-9][0-9]*$")
                26. then
                27. # 如果answer是选择菜单的数字,则获取该数字对应的字符串
                 28. if [ $answer -le ${#LUNCH_MENU_CHOICES[@]} ]
                29. then
                30. selection=${LUNCH_MENU_CHOICES[$(($answer-$_arrayoffset))]}
                31. fi
                32. # 如果 answer字符串匹配 *-*模式(*的开头不能为-)
                33. elif (echo -n $answer | grep -q -e "^[^\-][^\-]*-[^\-][^\-]*$")
                34. then
                35. selection=$answer
                36. fi
                37.
                38. if [ -z "$selection" ]
                39. then
                40. echo
                41. echo "Invalid lunch combo: $answer"
                42. return 1
                43. fi
                44.
                45. # special case the simulator
                46. if [ "$selection" = "simulator" ]
                47. then
                48. # 模拟器模式
                49. export TARGET_PRODUCT=sim
                50. export TARGET_BUILD_VARIANT=eng
                51. export TARGET_SIMULATOR=true
                52. export TARGET_BUILD_TYPE=debug
                53. else
                54.
                55. # 将 product-variant模式种的product分离出来
                56. local product=$(echo -n $selection | sed -e "s/-.*$//")
                57.
                58. # 检查之,调用关系 check_product()->get_build_var()->build/core/config.mk比较罗嗦,不展开了
                59. check_product $product
                60. if [ $? -ne 0 ]
                61. then
                62. echo
                63. echo "** Don't have a product spec for: '$product'"
                64. echo "** Do you have the right repo manifest?"
                65. product=
                66. fi
                67.
                68. # 将 product-variant模式种的variant分离出来
                69. local variant=$(echo -n $selection | sed -e "s/^[^\-]*-//")
                70.
                71. # 检查之,看看是否在 (user userdebug eng) 范围内
                72. check_variant $variant
                73. if [ $? -ne 0 ]
                74. then
                75. echo
                76. echo "** Invalid variant: '$variant'"
                77. echo "** Must be one of ${VARIANT_CHOICES[@]}"
                78. variant=
                79. fi
                80.
                81. if [ -z "$product" -o -z "$variant" ]
                82. then
                83. echo
                84. return 1
                 85. fi
                86. <span style="white-space:pre"> </span># 导出环境变量,这儿很重要,因为后面的编译系统都是依赖于这里定义的几个变量的
                87. export TARGET_PRODUCT=$product
                88. export TARGET_BUILD_VARIANT=$variant
                89. export TARGET_SIMULATOR=false
                90. export TARGET_BUILD_TYPE=release
                91. fi # !simulator
                92.
                93. echo
                94.
                95. # 设置到环境变量,比较多,不再一一列出,最简单的方法 set >env.txt 可获得
                96. set_stuff_for_environment
                97. # 打印一些主要的变量, 调用关系 printconfig()->get_build_var()->build/core/config.mk->build/core/envsetup.mk 比较罗嗦,不展开了
                98. printconfig
                99. }

由上面分析可知,lunch命令可以带参数和不带参数,最终导出一些重要的环境变量,从而影响编译系统的编译结果。导出的变量如下(以实际运行情况为例)

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

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

你可能感兴趣的:(android)