標籤:筆記 .sh path i386 64位 width shared net zlib
2018-05-23
Android6.0.0_r1源碼編譯
簡要說明:android源碼編譯的四個流程:1.源碼下載;2.構建編譯環境;3.編譯源碼;4運行.下文也將按照該流程講述。
主機環境
Ubuntu 16.04 LTS
Android 6.0.0_r1
Open JDK 7
源碼下載
由於某牆的原因,這裡我們採用國內的鏡像源進行下載.
目前,可用的鏡像源一般是科大和清華的,具體使用差不多,這裡我選擇清華大學鏡像進行說明.(參考:科大源,清華源)
Google採用Repo管理Android源碼,所以要先下載Repo工具.
通過執行以下命令實現repo工具的下載和安裝:
1 mkdir ~/bin2 PATH=~/bin:$PATH3 curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo4 chmod a+x ~/bin/repo
建立源碼檔案夾
熟悉Git的同學都應該知道,我們需要為項目在本地建立對應的倉庫.同樣,這裡為了方便對代碼進行管理,我們為其建立一個檔案夾.這裡我在目前使用者目錄下建立了source檔案夾,後面所有的下載的源碼和編譯出的產物也都放在這裡,命令如下:
1 mkdir source2 cd source
初始化倉庫
我們將上面的source檔案夾作為倉庫,現在需要來初始化這個倉庫了.通過執行初始化倉庫命令可以擷取AOSP項目master上最新的代碼並初始化該倉庫,命令如下:
1 repo init -u https://aosp.tuna.tsinghua.edu.cn/platform/manifest -b android-6.0.0_r1
(AOSP項目當前所有的分支列表參看:分支列表)-b參數表示指定擷取某個特定的Android版本,這裡我們指定android-6.0.0_r1.
同步源碼到本地
初始化倉庫之後,就可以開始正式同步代碼到本地了,命令如下:
1 repo sync
將該檔案儲存在源碼目錄下,也就是我們的source目錄,然後執行該指令碼即可,安心的等待源碼下載完成,預計花費3小時左右就可下載完成。由於網路原因,在使用repo sync同步代碼的過程中會多次出錯,這裡我們採用一個shell指令碼使其同步失敗時自動重試:
1 #!/bin/bash 2 echo "======start repo sync======" 3 repo sync # 第一次下載android原始碼4 while [ $? != 0 ]; do5 echo "======sync failed, re-sync again======" 6 sleep 27 repo sync # 如果出錯,隔2秒後回繼續調用repo sync下載android原始碼8 done
注意:由於 .repo 目錄是隱藏目錄,因此在下載完成之前你是不看到啥東西的。
構建編譯環境
硬體要求:
64位的作業系統只能編譯2.3.x以上的版本,如果你想要編譯2.3.x以下的,那麼需要32位的作業系統.
軟體要求:
作業系統,在AOSP開源中,主分支使用Ubuntu長期版本開發與測試的,因此也建議你使用Ubuntu進行編譯,下面我們列出不同版本的的Ubuntu能夠編譯那些android版本:
Android版本 |
編譯要求的Ubuntu最低版本 |
Android 6.0至AOSP master |
Ubuntu 14.04 |
Android 2.3.x至Android 5.x |
Ubuntu 12.04 |
Android 1.5至Android 2.2.x |
Ubuntu 10.04 |
JDK版本,
Android版本 |
編譯要求的JDK版本 |
AOSP的Android主線 |
OpenJDK 8 |
Android 5.x至android 6.0 |
OpenJDK 7 |
Android 2.3.x至Android 4.4.x |
Oracle JDK 6 |
Android 1.5至Android 2.2.x |
Oracle JDK 5 |
更具體的可以參看:Google源碼編譯要求
安裝JDK
由於我們安裝的是android6.0,我們需要採用OpenJDK7,而但是在Ubuntu 15.04及之後的版本的線上安裝庫中只支援openjdk8和openjdk9的安裝,因此在Ubuntu16.04上安裝OpenJDK7需要執行下面命令:
1 sudo add-apt-repository ppa:openjdk-r/ppa2 sudo apt-get update3 sudo apt-get install openjdk-7-jdk
配置OpenJDK,開啟/etc/profile檔案:
1 sudo gedit /etc/profile
在末尾追加下面代碼:
1 # jdk path config2 export JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd643 export JRE_HOME=${JAVA_HOME}/jre4 export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib5 export PATH=${JAVA_HOME}/bin:$PATH
修改/etc/profile檔案重啟生效:
1 source /etc/profile
檢查OpenJDK配置是否正確:
1 java -version
配置成功如:
安裝環境依賴:(16.04環境依賴)
1 sudo apt-get install libx11-dev:i386 libreadline6-dev:i386 libgl1-mesa-dev g++-multilib 2 sudo apt-get install -y git flex bison gperf build-essential libncurses5-dev:i386 3 sudo apt-get install tofrodos python-markdown libxml2-utils xsltproc zlib1g-dev:i386 4 sudo apt-get install dpkg-dev libsdl1.2-dev libesd0-dev 5 sudo apt-get install git-core gnupg flex bison gperf build-essential 6 sudo apt-get install zip curl zlib1g-dev gcc-multilib g++-multilib 7 sudo apt-get install libc6-dev-i386 8 sudo apt-get install lib32ncurses5-dev x11proto-core-dev libx11-dev 9 sudo apt-get install libgl1-mesa-dev libxml2-utils xsltproc unzip m410 sudo apt-get install lib32z-dev ccache
注意:不同Ubuntu所需要的依賴不同,一定要安裝正確。
修改源碼:
修改source/art/build/Android.common_build.mk檔案,定位到75行,將下面代碼:
1 ifneq ($(WITHOUT_HOST_CLANG),true)
改為:
1 ifeq ($(WITHOUT_HOST_CLANG),false)
修改的目的是把CLANG編譯選項關閉。
上面的工作完成後,基本的預準備工作就已經完成。下面是正式的編譯步驟。
初始化編譯環境:
(目前的目錄在包含Android源碼的source目錄下)
確保上述過程完成後,接下來我們需要初始化編譯環境
1)在.bashrc檔案末尾添加:export USER_CCACHE = 1
1 echo export USER_CCACHE=1 >> ~/.bashrc
2)為了提高編譯效率,設定編譯器快取:
1 prebuilts/misc/linux-x86/ccache/ccache -M 50G
3)接著匯入編譯Android源碼所欲要得環境變數和其他參數:
1 source build/envsetup.h
執行命令結果如下:
不難發現該命令只是引入了其他執行指令碼,至於這些指令碼做什麼,目前不在本文中細說.
該命令執行成功後,我們會得到了一些有用的命令,比如最下面要用到的lunch命令.
編譯源碼
執行lunch命令
1 lunch
控制台會列出所有的編譯目標,如下:
這裡選擇aosp_arm-eng,表示產生arm架構的工程師版本,擁有最大許可權(root),此外還附帶了許多debug工具。
這裡輸入1之後,會輸出一些環境變數資訊:
開始編譯
通過make指令進行代碼編譯,該指令通過-j參數來設定參與編譯的線程數量,以提高編譯速度.比如這裡我們設定8個線程同時編譯:
1 make -j8
如果一切順利的話,在幾個小時之後,便可以編譯完成.看到### make completed successfully (01:18:45(hh:mm:ss)) ###表示你編譯成功了.需要注意的是,參與編譯的線程並不是越多越好,通常是根據你機器cup的核心來確定:core*2,即當前cpu的核心的2倍.比如,我現在的筆記本是雙核四線程的,因此根據公式,最快速的編譯可以make -j8.
(通過cat /proc/cpuinfo查看相關cpu資訊)
運行模擬器
編譯完成之後,就可以通過下面命令運行Android虛擬機器了,命令如下:
1 source build/envsetup.sh2 lunch(選擇剛才你設定的目標版本,比如這裡了我選擇的是1)3 emulator
不出意外,稍作等待,會看到運行介面:像lunch,emulator這些命令是屬於envsetup.sh的,如果你沒有離開剛編譯完源碼的終端,直接輸入emulator也是可以的。
Android源碼的編譯到此就完成了,我在編譯過程中遇到了一些問題,多半是依賴沒有裝全,上網查16.04裝Android6的文章,對著重新過一遍依賴就可以了。
POC源碼編譯
這裡針對的是對Android源碼有所依賴的程式的編譯,因為要編譯的POC程式大多要類比用戶端的底層與系統服務通訊,需要調用一些用戶端底層的函數,如下:
如果在Android.mk裡面配置標頭檔和庫檔案路徑的話,會很麻煩,而且標頭檔還有嵌套,不太好配置,我也沒找到配置庫檔案路徑的參數,最終選擇了源碼編譯環境中的mmm指令進行編譯。
下面是編譯步驟:
1)建立一個目錄裡面存放poc.cpp和Android.mk.
Android.mk中的內容是:
1 LOCAL_PATH := $(call my-dir)2 include $(CLEAR_VARS)3 LOCAL_MODULE := poc4 LOCAL_MODULE_TAGS := optional5 LOCAL_SRC_FILES := poc.cpp6 LOCAL_CFLAGS += -march=armv47 LOCAL_SHARED_LIBRARIES := libbinder libutils libmedia libstagefright_foundation8 include $(BUILD_EXECUTABLE)
這些大部分參數在官方NDK入門指南都有介紹,說兩個:
LOCAL_MODULE_TAGS :=optional,表示在任何版本(usr,debug,eng)下都編譯。
include $(BUILD_EXECUTABLE),表示產生可執行檔。
LOCAL_CFLAGS += -march=armv4,相當於在編譯時間指定了-march參數,gcc將不會再用相容的指令去編譯,而是根據指定的CPU結構,採用其特定的指令集去產生二進位代碼。因此,當你確定所編譯的程式只會在特定的環境中運行時,可以使用-march參數來指定CPU架構,這樣編譯器就可以根據你的CPU架構進行指令上的最佳化,而這個指定帶來的後果就是,如果你將程式放在其他機器上運行,有可能得到Illegal instruction的運行錯誤。
2)進入Android源碼目錄,初始化源碼編譯環境
1 cd source(android源碼目錄)2 source build/envsetup.sh3 lunch 1
mmm屬於envsetup.sh的指令,作用是編譯指定目錄下的所有模組。
3)利用mmm進行編譯
1 mmm AndroidWP/jni(poc.cpp目錄)
使用mmm的好處是,它會自動尋找標頭檔和庫檔案路徑,把要編譯的模組作為android的一個內部模組進行編譯,輸出到out裡。所以只需要在Android.mk中指定共用庫的名字就可以了。
注意:在使用mmm編譯的前幾次,它會預設執行make clean操作,會把你之前編譯安裝的android源碼的輸出全部remove,目前我就是只能再重新編譯一遍android源碼,不過這就很快了,更多的是copy和install的操作,不要驚慌。
具體的mmm指令細節沒有深究,有興趣可以上網看源碼分析。
編譯完之後,利用adb把程式push到android機上,運行即可。
參考:
51718187
51487585
[轉組第10天] | Android6.0.0_r1源碼編譯和POC程式的編譯