标签:笔记 .sh path i386 64位 width shared net zlib
2018-05-23
简要说明:android源码编译的四个流程:1.源码下载;2.构建编译环境;3.编译源码;4运行.下文也将按照该流程讲述。
主机环境
Ubuntu 16.04 LTS
Android 6.0.0_r1
Open JDK 7
源码下载
由于某墙的原因,这里我们采用国内的镜像源进行下载.
目前,可用的镜像源一般是科大和清华的,具体使用差不多,这里我选择清华大学镜像进行说明.(参考:科大源,清华源)
Google采用Repo管理Android源码,所以要先下载Repo工具.
通过执行以下命令实现repo工具的下载和安装:
1 mkdir ~/bin 2 PATH=~/bin:$PATH 3 curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo 4 chmod a+x ~/bin/repo
建立源码文件夹
熟悉Git的同学都应该知道,我们需要为项目在本地创建对应的仓库.同样,这里为了方便对代码进行管理,我们为其创建一个文件夹.这里我在当前用户目录下创建了source文件夹,后面所有的下载的源码和编译出的产物也都放在这里,命令如下:
1 mkdir source 2 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 ]; do 5 echo "======sync failed, re-sync again======" 6 sleep 2 7 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/ppa 2 sudo apt-get update 3 sudo apt-get install openjdk-7-jdk
配置OpenJDK,打开/etc/profile文件:
1 sudo gedit /etc/profile
在末尾追加下面代码:
1 # jdk path config 2 export JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64 3 export JRE_HOME=${JAVA_HOME}/jre 4 export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib 5 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 m4 10 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.sh 2 lunch(选择刚才你设置的目标版本,比如这里了我选择的是1) 3 emulator
不出意外,稍作等待,会看到运行界面:像lunch,emulator这些命令是属于envsetup.sh的,如果你没有离开刚编译完源码的终端,直接输入emulator也是可以的。
Android源码的编译到此就完成了,我在编译过程中遇到了一些问题,多半是依赖没有装全,上网查16.04装Android6的文章,对着重新过一遍依赖就可以了。
这里针对的是对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 := poc 4 LOCAL_MODULE_TAGS := optional 5 LOCAL_SRC_FILES := poc.cpp 6 LOCAL_CFLAGS += -march=armv4 7 LOCAL_SHARED_LIBRARIES := libbinder libutils libmedia libstagefright_foundation 8 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.sh 3 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机上,运行即可。
参考:
https://blog.csdn.net/dd864140130/article/details/51718187
https://blog.csdn.net/fuchaosz/article/details/51487585
[转组第10天] | Android6.0.0_r1源码编译和POC程序的编译
标签:笔记 .sh path i386 64位 width shared net zlib
原文地址:https://www.cnblogs.com/nww-570/p/9080136.html