浅谈android源码之build

1. 前言

这篇文章主要是整理之前的学习系统编译时候的经验,欢迎大家技术交流。如需转载,请标明出处!

2. 准备环境

apt install curl
apt install repo
apt update
sudo apt-get install openjdk-8-jdk
sudo apt-get install libx11-dev:i386 libreadline6-dev:i386 libgl1-mesa-dev g++-multilib
sudo apt-get install -y git flex bison gperf build-essential libncurses5-dev:i386
sudo apt-get install tofrodos python-markdown libxml2-utils xsltproc zlib1g-dev:i386
sudo apt-get install dpkg-dev libsdl1.2-dev libesd0-dev
sudo apt-get install git-core gnupg flex bison gperf build-essential
sudo apt-get install zip curl zlib1g-dev gcc-multilib g++-multilib
sudo apt-get install libc6-dev-i386
sudo apt-get install lib32ncurses5-dev x11proto-core-dev libx11-dev
sudo apt-get install libgl1-mesa-dev libxml2-utils xsltproc unzip m4
sudo apt-get install lib32z-dev ccache

3.下载源码

1.创建bin
mkdir ~/bin  
PATH=~/bin:$PATH  
curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo  
chmod a+x ~/bin/repo  

2.修改~/.bashrc,~/bin/repo
vim ~/.bashrc
增加
export REPO_URL='https://mirrors.tuna.tsinghua.edu.cn/git/git-repo/'
vim ~/bin/repo
替换
REPO_URL = 'https://gerrit-google.tuna.tsinghua.edu.cn/git-repo'

3.配置用户名
git config --global user.email "allengao@pacewear.cn"
git config --global user.name "allengao"

4.拉取并初始化
mkdir soucre
cd source
repo init -u https://aosp.tuna.tsinghua.edu.cn/platform/manifest

5.同步数据
repo sync

4. 编译源码

为什么需要弄清楚系统编译呢,这是因为我们做系统级别的研发是避免不了不断编译之后进行调试的,而且编译之后生成的产物最终会拷贝到手机中相应的分区位置生效的。

编译系统的规则注意存在于系统源码的build目录,我们需要编译系统常用的几个命令,顺序如下:
source ./build/envsetup.sh
lunch combo
make -j8

其中第一行命令是初始化编译环境,将envsetup.sh里的所有用到的命令加载到环境变量里去;
第二行命令是加载所需编译的产品,combo是个变量,可以是数字,也可以是个字符串,根据实际情况选择;
第三行命令是真正开始编译源码的命令,后面的j8是编译的时候开8个线程进行编译,加快编译的效率。

4.1 source原理

我们常用来执行shell脚本的方法有四种,以执hello.sh脚本为例

  1. bash hello.sh
  2. . hello.sh
  3. source hello.sh

第一种方法执行shell脚本时都是在当前shell(称为父shell)开启一个子shell环境,此shell脚本就在这个子shell环境中执行,shell脚本执行完后子shell环境随即关闭,然后又回到父shell中。后面两种方式则是在当前shell中执行的,source命令也被称为点命令(.)。再看envsetup.sh脚本中定义多个函数,比如lunch,m,mm,mmm,cgrep,相当于将这些函数设进环境变量,为后面编译提供函数支持,后面可以直接在命令行输入函数名调用函数,而如果使用bash build/envsetup.sh就不能达到这个效果。

4.2 lunch原理

我们分析一下envsetup.sh脚本中的lunch函数,从上往下看:
1.若lunch后面直接带参数,将参数值赋值给变量answer,若lunch后面不带参数,则打印处所有的target product和variant菜单提供用户选择,代码如下:
在这里插入图片描述

2.如果用户在菜单中没有选择,直接回车,则为系统缺省的aosp_arm-eng。如果answer是选择菜单的数字,则获取该数字对应的字符串并赋值给selection变量,如果不是数字,answer字符串匹配 *-*模式(*的开头不能为-),就将变量answer的值赋值给变量selection,代码如下:
在这里插入图片描述

3.导出环境变量,这里很重要,因为后面的编译系统都是依赖于这里定义的几个变量的,代码如下:
在这里插入图片描述
4.设置到环境变量,并打印一些主要的变量,代码如下:
在这里插入图片描述

4.3 make原理

make命令就是查找并执行Makefile或makefile文件,而当输入make命令编译系统源码的时候,会在当前根目录查找Makefile文件,其中Makefile文件所含内容只有简单的一句:
在这里插入图片描述

作用就是引入main.mk文件
而当使用m编译系统的时候,我们同样可以看到是最终执行main.mk文件:
在这里插入图片描述

main.mk 里面比较复杂,其主要做了这几个事情
1.include mk文件:
在这里插入图片描述

下面是引用树结构:
在这里插入图片描述

这里特别说明两个比较重要的mk文件,config.mk与definitions.mk。
config.mk 中定义了许多的常量,这其中的每个常量描述了一种类型模块的编译方式,这些常量有:
• BUILD_HOST_STATIC_LIBRARY
• BUILD_HOST_SHARED_LIBRARY
• BUILD_STATIC_LIBRARY
• BUILD_SHARED_LIBRARY
• BUILD_EXECUTABLE
• BUILD_HOST_EXECUTABLE
• BUILD_PACKAGE
• BUILD_PREBUILT
• BUILD_MULTI_PREBUILT
• BUILD_HOST_PREBUILT
• BUILD_JAVA_LIBRARY
• BUILD_STATIC_JAVA_LIBRARY
• BUILD_HOST_JAVA_LIBRARY
definitions.mk在其中定义了大量的函数。这些函数都是 Build 系统的其他文件将用到的。例如:my-dir,all-subdir-makefiles,find-subdir-files,sign-package等。

2.执行Target

根据Makefile执行target规则,make的时候如果不带参,会默认执行第一个出现的target,即droid这个目标:
在这里插入图片描述
我们可以看到droid目标下并没有实际的操作,我们继续往下找可以看到main.mk文件中其他地方有几处对droid规则的定义:
在这里插入图片描述

这里会根据TARGET_BUILD_APPS变量的值是否为空来判断走不同的分支。如果不为空,则droid的先决条件是apps_only,否则droid的先决条件是droidcore和dist_files,我们使用默认的make命令编译android系统的话这里的TARGET_BUILD_APPS的值为空,所以走不为空情况下的这个分支。

我们再来分别看一下droid目标所依赖的droidcore和dist_files
droidcore节点:
在这里插入图片描述
dist_files节点:
在这里插入图片描述
依赖目标树如下:

在这里插入图片描述
通过包含android源码的mk文件,以及加载所有的依赖,以达到编译整个android系统源码的目的。

ps:这里还需要注意的是各个编译变量的编译原理,这里不再赘述。

5. 编译模块模板

  1. 编译可执行程序的模板:
     LOCAL_PATH := $(call my-dir)
     include $(CLEAR_VARS)
     LOCAL_SRC_FILES:= main.c
     LOCAL_MODULE:= test_exe
     include $(BUILD_EXECUTABLE)
  1. 编译静态库的模板:
     LOCAL_PATH := $(call my-dir)
     include $(CLEAR_VARS)
     LOCAL_SRC_FILES:= \
               helloworld.c
     LOCAL_MODULE:= libtest_static
     include $(BUILD_STATIC_LIBRARY)
  1. 编译动态库的模板:
     LOCAL_PATH := $(call my-dir)
     include $(CLEAR_VARS)
     LOCAL_SRC_FILES:= \
               helloworld.c
     LOCAL_MODULE:= libtest_shared
     TARGET_PRELINK_MODULES := false
      include $(BUILD_SHARED_LIBRARY)
  1. 编译apk的模板
     LOCAL_PATH := $(call my-dir)
     include $(CLEAR_VARS)
     LOCAL_SRC_FILES:= \
               Helloworld.apk
     LOCAL_PACKAGE_NAME:= helloapk
      include $( BUILD_PACKAGE)
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值