編輯:關於android開發
近日接手了後續android新平台項目搭建的任務。
本文內容基於sprd公司提供的android5.1源碼。
我們代碼一般情況下是從芯片商SPRD/MTK獲得的。
源碼的編譯上,一般還是和google官網(http://source.android.com/source/building.html)上要求的一致。分為三步:
1.source build/envsetup.sh
2.lunch xxx
3.make -j8 2>&1 |tee build.log
4.mmm "模塊"可以編譯單獨的模塊(要全編譯後才可以編譯模塊)
android的編譯是基於的linux的make命令的。Make命令在執行的時候,默認會在當前目錄找到一個Makefile文件,然後根據Makefile文件中的指令來對代碼進行編譯。
Makefile文件最基礎的功能就是描述文件之間的依賴關系,以及怎麼處理這些依賴關系。
整個android源碼的編譯就是由根目錄的Makefile文件來執行的。
現在我們就了解下我們編譯過程中的命令做了哪些事情。
執行build/envsetup.sh腳本(ps: source xx.sh命令就是 執行一個腳本的意思。那為什麼不直接./xxx.sh呢? 見這篇文章http://blog.csdn.net/coofive/article/details/671835)
build/envsetup.sh腳本裡做了哪些事情呢?
這些 envsetup.sh裡面有哪些代碼呢
舉一個例子 device/sprd/zsl1805/lava/envsetup.sh
add_lunch_combo zsl1805_lava-userdebug add_lunch_combo zsl1805_lava-user
add_lunch_combo是什麼東西?我們先不管,往下看。
如:lunch mmm add_lunch_combo等。
lunch:用來初始化編譯環境,例如設置環境變量和指定目標產品型號。後面再說
m:相當於是在執行make命令。對整個Android源碼進行編譯。
mm:如果是在Android源碼根目錄下執行,那麼就相當於是執行make命令對整個源碼進行編譯。如果是在Android源碼根目錄下的某一個子目錄執行,那麼就在會在從該子目錄開始,一直往上一個目錄直至到根目錄,尋找是否存在一個Android.mk文件。如果存在的話,那麼就通過make命令對該Android.mk文件描述的模塊進行編譯。
mmm:後面可以跟一個或者若干個目錄。就是編譯模塊了。如mmm "packages/apps/Launcher3"
add_lunch_combo:
1 unset LUNCH_MENU_CHOICES
2 function add_lunch_combo()
3 {
4 local new_combo=$1
5 local c
6 for c in ${LUNCH_MENU_CHOICES[@]} ; do
7 if [ "$new_combo" = "$c" ] ; then
8 return
9 fi
10 done
11 LUNCH_MENU_CHOICES=(${LUNCH_MENU_CHOICES[@]} $new_combo)
12 }
這裡我們只要知道add_lunch_combo把"zsl1805_lava_userdebug"和"zsl1805_lava_user"add到"LUNCH_MENU_CHOICES"裡了。
到這裡,source build/envsetup.sh的工作就做完了。
此時可以在shell命令行裡看到
including device/sprd/zsl1805/lava/vendorsetup.sh的字樣,這個文件確實被加載進來了
我們先看下build/envsetup.sh中lunch函數的代碼
1 #打印"LUNCH_MENU_CHOICES"中所有值
2 function print_lunch_menu()
3 {
4 local uname=$(uname)
5 echo
6 echo "You're building on" $uname
7 echo
8 echo "Lunch menu... pick a combo:"
9
10 local i=1
11 local choice
12 for choice in ${LUNCH_MENU_CHOICES[@]}
13 do
14 echo " $i. $choice"
15 i=$(($i+1))
16 done
17
18 echo
19 }
20
21 function lunch()
22 {
23 local answer
24 #如果只輸入了lunch命令,會打印"LUNCH_MENU_CHOICES"中所有值
25 if [ "$1" ] ; then
26 answer=$1
27 else
28 print_lunch_menu
29 echo -n "Which would you like? [aosp_arm-eng] "
30 read answer
31 fi
32
33 #判斷lunch後面的值是不是LUNCH_MENU_CHOICES中的值,如果是,則把這個值賦給selection
34 local selection=
35
36 if [ -z "$answer" ]
37 then
38 selection=aosp_arm-eng
39 elif (echo -n $answer | grep -q -e "^[0-9][0-9]*$")
40 then
41 if [ $answer -le ${#LUNCH_MENU_CHOICES[@]} ]
42 then
43 selection=${LUNCH_MENU_CHOICES[$(($answer-1))]}
44 fi
45 elif (echo -n $answer | grep -q -e "^[^\-][^\-]*-[^\-][^\-]*$")
46 then
47 selection=$answer
48 fi
49
50 if [ -z "$selection" ]
51 then
52 echo
53 echo "Invalid lunch combo: $answer"
54 return 1
55 fi
56
57 export TARGET_BUILD_APPS=
58 export CONFIG_TARGET_BUILD_TYPE=
59
60
61 #對selection值進行分割操作,得到product和variant
62
63 local product=$(echo -n $selection | sed -e "s/-.*$//")
64 check_product $product
65 if [ $? -ne 0 ]
66 then
67 echo
68 echo "** Don't have a product spec for: '$product'"
69 echo "** Do you have the right repo manifest?"
70 product=
71 fi
72
73 local variant=$(echo -n $selection | sed -e "s/^[^\-]*-//")
74 check_variant $variant
75 if [ $? -ne 0 ]
76 then
77 echo
78 echo "** Invalid variant: '$variant'"
79 echo "** Must be one of ${VARIANT_CHOICES[@]}"
80 echo "** Vinton.Wang -----------> variant:'$variant'"
81 export CONFIG_TARGET_BUILD_TYPE=$(echo $variant | tr '[a-z]' '[A-Z]')
82 echo "** Vinton.Wang -----------> type:'$CONFIG_TARGET_BUILD_TYPE'"
83 variant="userdebug"
84 fi
85
86 if [ -z "$product" -o -z "$variant" ]
87 then
88 echo
89 return 1
90 fi
91 #得到TARGET_PRODUCT TARGET_BUILD_VARIANT TARGET_BUILD_TYPE三個值
92 export TARGET_PRODUCT=$product
93 export TARGET_BUILD_VARIANT=$variant
94 export TARGET_BUILD_TYPE=release
95 export ARCH=$(gettargetarch)
96 echo "############# ${ARCH} ##############"
97
98 echo
99 echo
100 check_hq_version
101 set_stuff_for_environment #設置環境變量
102 printconfig
103 }
另外,在check_product()和printconfig()兩個方法中,調用了get_build_var()函數。
# Get the exact value of a build variable.
function get_build_var()
{
T=$(gettop)
if [ ! "$T" ]; then
echo "Couldn't locate the top of the tree. Try setting TOP." >&2
return
fi
(\cd $T; CALLED_FROM_SETUP=true BUILD_SYSTEM=build/core \
command make --no-print-directory -f build/core/config.mk dumpvar-$1)
}
也就是說,在lunch的過程中,編譯了build/core/config.mk
總結一下Lunch流程:
1.判斷是不是沒有參數
2.判斷參數是否合法
3.將參數進行分割操作,得到TARGET_PRODUCT TARGET_BUILD_VARIANT
4.設置環境變量
如果我們直接輸入lunch,會有下面的界面出現
You're building on Linux
generic-eng simulator fs100-eng
Lunch menu... pick a combo:
1. generic-eng
2. simulator
3. fs100-eng
.....................
40. zsl1805_lava-userdebug
41. zsl1805_lava-user
然後,我們需要lunch zsl1805_lava-userdebug即可。
到此時,android編譯環境的初始化就完成了。
貼一張初始化完成之後,我們獲得的東西
下面就是執行編譯了。根目錄裡的Makefile文件中是這樣的
### DO NOT EDIT THIS FILE ### include build/core/main.mk ### DO NOT EDIT THIS FILE ###
Make其實就是按照main.mk的編譯規則來編譯的。
整個編譯過程還是比較復雜的,這裡有一張main.mk的編譯示意圖,基本涵蓋了所有編譯內容。這裡就不去深入研究了,如果對某些細節感興趣,可以看下面的參考資料再去深入學習。
我們只要知道,如果我們要對編譯過程中的流程修改,就按照這個圖找到相應的.mk文件進行修改。

參考資料:
Android編譯過程詳解(一):http://www.cnblogs.com/mr-raptor/archive/2012/06/07/2540359.html
Android編譯過程詳解(二):http://www.cnblogs.com/mr-raptor/archive/2012/06/08/2541571.html
Android開發藝術探索學習筆記(三),android藝術探索
Android開發藝術探索學習筆記(三),android藝術探索第三章 View的事件體系 3.1 View基礎知識 3.1.1 什麼是view
使用Android studio分析內存洩露
使用Android studio分析內存洩露 使用Android studio分析內存洩露 This post is a permitted tra
android:Intent匹配action,category和data原則,androidintent
android:Intent匹配action,category和data原則,androidintent1.當你在androidmanifest裡面定義了一個或多個act
Android開發3:Intent、Bundle的使用和ListView的應用 、RelativeLayout(相對布局)簡述(簡單通訊錄的實現),relativelayout
Android開發3:Intent、Bundle的使用和ListView的應用 、RelativeLayout(相對布局)簡述(簡單通訊錄的實現),relativelay
Android應用項目中BaseAdapter、SimpleAdapter和ArrayAdapter中的三種適配器,simplearrayadapter
Android應用項目中BaseAdapter、SimpleAdapte