227 lines
10 KiB
Markdown
227 lines
10 KiB
Markdown
### source build/envsetup.sh
|
||
|
||
本文件的作用是初始化编译环境,并引入一些辅助命令。
|
||
|
||
- 定义hmm, 加载编译时使用的命令。
|
||
|
||
- 定义 printconfig, 显示当前构建的配置信息。
|
||
|
||
- 定义 add_lunch_combo, 用来给lunch命令添加编译选项。
|
||
|
||
本函数的处理过程是,遍历数组LUNCH_MENU_CHOICES,判断要添加的编译选项是否在数组里,如在数组里则直接返回,如不在数组里则将其添加到数组里。
|
||
|
||
|
||
- 添加了6条默认的选项:aosp_*。
|
||
- 定义print_lunch_menu,用于列出所有的编译选项。
|
||
- 定义lunch,用于让用户指定编译选项。
|
||
- 定义_lunch,用于为lunch命令提供参数自动补齐的功能。
|
||
- 这是一条complete命令,指定由_lunch实现lunch命令里参数自动补齐的功能。
|
||
- 659~668, m, 在源码树的根目录执行make
|
||
- 687~723, mm, 构建当前目录下的模块
|
||
- 725~770, mmm, 构建指定目录下的模块
|
||
- 823~831,croot,切换到源码树的根的目录
|
||
- 1329~1332, jgrep, 在所有java文件上执行grep
|
||
- 1334~1337, cgrep, 在所有c/c++文件上执行grep
|
||
- 1339~1342, resgrep, 在所有res/*.xml文件上执行grep
|
||
- 1590~1632, godir, 转到包含某个文件的目录路径
|
||
- 在文件的末尾,查找vendorsetup.sh脚本并加载它。openthos的编译选项就是在这里被加载的。
|
||
|
||
|
||
|
||
### lunch
|
||
|
||
lunch命令定义在build/envsetup.sh里,用来让用户选择编译设备与编译类型。其执行步骤如下:
|
||
|
||
1. 定义变量answer(用以代表用户的选择),如果命令里给了参数则直接使用给定的参数,否则列出所有的编译选项让用户选项。
|
||
|
||
2. 定义变量selection(用以代表变量answer所对应的字符串),如果用户没选择则使用默认选项aosp_arm-eng,如果用户输入的是数字则使用该数字对应的字符串,如果用户输入的是字符串则直接使用该字符串。
|
||
|
||
3. 定义变量product,将selection里"-"的前面部分放在变量product里,如编译openthos则其值为"openthos"。
|
||
|
||
4. 定义变量variant,将selection里两个"-"之间的部分放在变量variant里,如编译openthos则其值为"x86_64"。
|
||
|
||
5. 定义变量version,将seleciton里"-"之后的部分放在version里,如编译openthos则其值可能是"user"、"userdebug"或"eng"。eng适用于开发阶段,userdebug适用于调试阶段,user适用于最终发布阶段。
|
||
|
||
6. 定义如下3个环境变量
|
||
|
||
```
|
||
export TARGET_PRODUCT=$product
|
||
export TARGET_BUILD_VARIANT=$variant
|
||
export TARGET_BUILD_TYPE=release
|
||
```
|
||
|
||
7. set_stuff_for_environment函数,设置一些环境变量。
|
||
|
||
8. printconfig函数,打印一些主要的变量。
|
||
|
||
### make
|
||
|
||
- make命令定义在build/envsetup.sh里。
|
||
|
||
```
|
||
function make()
|
||
{
|
||
_wrap_build $(get_make_command) "$@"
|
||
}
|
||
```
|
||
|
||
- 依据`get_make_command`函数的定义,$(get_make_command)的值是"build/soong/soong_ui.bash --make-mode"。
|
||
|
||
- 在`_wrap_build`函数可见,第二行"$@"已经执行完所有的编译过程了,其它部分只不过是输出一些统计信息而已。
|
||
|
||
- build/soonn/soong_ui.bash。首先执行build/soong/cmd/microfactory/microfactory.bash,定义了两个工具函数,`getoutdir`用来查找out目录,`build_go`用来编译所需的二进制(参数1是所要编译的二进制的名字,参数2是包名);然后用build_go来编译soong_ui,最后执行的是`out/soong_ui $@`完成构建的过程。
|
||
|
||
- 函数build_go的执行逻辑:如果$mf_bin存在且$mf_version的值等于$mf_version_file里保存的值,说明$mf_bin存在且是最新的,此时它就是$mf_cmd;否则说明$mf_bin不存在或它的版本不是最新的,这时就需要构建新的$mf_cmd,它的值为`go run $mf_src/microfactory.go`。`$mf_cmd ...`那行是真正干活的,-s用来指示microfactory的源码目录,-b用来指示microfactory二进制的位置,-pkg-path是从包前缀到文件路径的映射,-trimpath用于从记录的源文件路径中删除前缀,-o用于指定输出文件的名称。
|
||
|
||
#### 构建的过程
|
||
|
||
构建的起点在`build/core/main.mk`,可以看到整个文件的结构如下:
|
||
|
||
```
|
||
ifndef KATI
|
||
...
|
||
else # KATI
|
||
...
|
||
endif # KATI
|
||
```
|
||
|
||
由于没有定义KATI,所以走的是ifndef流程。MAKECMDGOALS是make执行时后面的参数,这意味着不管执行什么目标最终都执行的都是run_soong_ui这个目标。这样编译的控制权就交到了soong手上,后面的事就跟make没有关系了。
|
||
|
||
soong_ui代码在`build/soong/cmd/soong_ui/main.go`,真正干活的是main函数里的最后一句:
|
||
|
||
```
|
||
build.Build(buildCtx, config, build.BuildAll)
|
||
```
|
||
|
||
build.Build在`ui/build/build.go`,从中可以看到执行soong的流程:
|
||
|
||
1. `runMakeProductConfig`在ui/build/make.go,用来配置编译参数。在这里可以看到[第一段输出](# 第一段输出)
|
||
|
||
2. `runSoongBootstrap`和`runSoong`在ui/build/soong.go,分别运行的是`./bootstrap.bash`和`soong`两个命令。在这里可以看到[第二段输出](# 第二段输出)和[第三段输出](# 第三段输出)
|
||
|
||
`./bootstrap.bash`的最后一句会执行`build/blueprint/bootstrap.bash $@`,如不带参数则生成minibp,如带参数则生成一个基于Blueprint的构建系统。
|
||
|
||
3. `runKati`在ui/build/kati.go,运行的是ckati命令。把所有的Android.mk文件生成ninja文件。
|
||
|
||
4. `createCombinedBuildNinjaFile`在ui/build/build.go,在out/combined-openthos_x86_64.ninja文件里用include关键字把前两步生成的ninja文件包含进来。
|
||
|
||
5. `runNinja`在ui/build/ninja.go,运行ninja命令执行构建过程,所使用的配置文件就是第四步生成的combined-openthos_x86_64.ninja。在这里看到[第四段输出](# 第四段输出)
|
||
|
||
#### 第一段输出
|
||
|
||
输出的是关于编译环境的若干变量。
|
||
|
||
#### 第二段输出
|
||
|
||
在`build/soong/build.ninja.in`,编译生成`out/soong/.bootstrap`下的文件。源文件在build/blueprint。
|
||
|
||
#### 第三段输出
|
||
|
||
搜集所有的`Android.bp`文件生成build.ninja。
|
||
|
||
#### 第四段输出
|
||
|
||
详细的编译过程
|
||
|
||
##### 第四段之生成oto_img
|
||
|
||
在bootable/newinstaller/Android.mk
|
||
|
||
```
|
||
# 1. 从175行可见,OTO_IMAGE即oto_img
|
||
oto_img: $(OTO_IMAGE)
|
||
# 2. OTO_IMAGE详见143~158行
|
||
# OTO_IMAGE: openthos_x86_64_oto.img
|
||
# OTO_INITRD_RAMDISK:oto_initrd.img
|
||
# OTO_BILT_IMG: ramdisk.img install.img system.sfs kernel
|
||
# DATA_IMG: data.img
|
||
143:$LOCAL_PaTH是/bootable/newinstaller
|
||
144:把$LOCAL_PATH/install/refind/efi目录压缩为$REFIND。$PRODUCT是out/target/product/openthos/,$REFIND是$PRODUCT/efi.tar.bz2
|
||
145:把$PRODUCT_OUT/oto_initrd.img复制到$PRODUCT_OUT/initrd.img。$PRODUCT_OUT是out/target/product/openthos/
|
||
146~149:统计依赖文件的大小
|
||
150:把$REFIND的大小加到size上,且再增加8k大小
|
||
151:把size调大了一点。size=size+62+(size/100)
|
||
152:创建($OTO_IMAGE).fat,即openthos_x86_64_oto.img.fat,然后用mkdosfs命令为其创建文件系统,大小为size。
|
||
153:把$LOCAL_PATH/install/refind/efi目录复制到openthos_x86_64_oto.img.fat镜像的顶层目录
|
||
154:在openthos_x86_64_oto.img.fat里创建OpenThos目录
|
||
155:把$LOCAL_PATH/install/refind/boto_linux.conf里的"BOOT_MODE="替换为$BOARD_KERNEL_CMDLINE,将输出重定向到out/target/product/openthos/boto_linux.conf
|
||
156:把$PRODUcT_OUT目录下的ramdisk.img install.img system.sfs initrd.img kernel efi.tar.bz2 boto_linux.conf复制到镜像openthos_x86_64_oto.img.fat的OpenThos目录下
|
||
157:创建openthos_x86_64_oto.img,然后使用edit_mbr命令,以bootable/newinstaller/editdisklbl/esp_layout.conf为layout配置文件,以openthos_x86_64_oto.img为要编辑的镜像,以openthos_x86_64_oto.img.fat为配置文件里的esp,创建启动镜像
|
||
158:删除openthos_x86_64_oto.img.fat和initrd.img
|
||
# 3. oto_initrd.img的生成详见76~83行
|
||
# 4. install.img的生成详见86~91行
|
||
```
|
||
|
||
ramdisk.img是在build/core/Makefile里生成的
|
||
|
||
```
|
||
580~596行
|
||
```
|
||
|
||
system.sfs
|
||
|
||
kernel是对源码目录kernel的编译,编译规则可能在build/core/Makefile或kernel/Makefile。
|
||
|
||
### 对镜像的分析
|
||
|
||
#### 挂载openthos_x86_64.img
|
||
|
||
```
|
||
sudo mount -o loop,offset=1048576 openthos_x86_64.img /mnt
|
||
# offset是使用fdisk -l命令计算出来的:起始扇区*每个扇区的大小
|
||
```
|
||
|
||
#### 解析initrd.img
|
||
|
||
通过对比可见initrd.img的内容来自于out/target/product/openthos/installer
|
||
|
||
```
|
||
file initrd.img # 发现它是gzip格式
|
||
cp initrd.img ~/initrd.img.gz && cd ~
|
||
gunzip initrd.img.gz # 生成initrd.img
|
||
file initrd.img # 发现它是cpio格式
|
||
mkdir initrd && cd initrd
|
||
cpio -i -F ../initrd.img # 把initrd.img的内容复制到initrd目录
|
||
```
|
||
|
||
#### 解析install.img
|
||
|
||
解压方法同initrd.img,通过对比可见其内容主要来自bootable/newinstaller/install
|
||
|
||
#### 解析ramdisk.img
|
||
|
||
解压方法同initrd.img,通过对比可见其内容主要来自out/target/product/openthos/root
|
||
|
||
#### 解析system.sfs
|
||
|
||
解压出system.img,然后挂载。通过对比可见其内容主要来自out/target/product/openthos/system
|
||
|
||
```
|
||
unsquashfs system.sfs
|
||
```
|
||
|
||
|
||
|
||
### 编译错误记录
|
||
|
||
> DEPMOD 4.9.109-android-x86_64-01316-g45b3cc90-dirty
|
||
>
|
||
> /root/szx/kernel/Makefile:1350: recipe for target '_modinst_post' failed
|
||
> make[1]: *** [_modinst_post] Error 255
|
||
> make[1]: Leaving directory '/root/szx/out/target/product/openthos/obj/kernel'
|
||
> Makefile:152: recipe for target 'sub-make' failed
|
||
> make: *** [sub-make] Error 2
|
||
> make: Leaving directory '/root/szx/kernel'
|
||
> [ 99% 99776/99781] build out/target/product/openthos/install.img
|
||
> ninja: build stopped: subcommand failed.
|
||
> 02:44:29 ninja failed with: exit status 1
|
||
|
||
问题分析:我的情况是少了kmod,把它安装上即可。`sudo apt install kmod`。另,还应检查`syslinux genisoimage gettext bc dosfstools mtools kmod`是否都安装齐全。另:从这里是看不出来问题在哪的,要从往前翻,找到真正错误的地方。
|
||
|
||
### 参考资料
|
||
|
||
[理解安卓build系统](https://www.ibm.com/developerworks/cn/opensource/os-cn-android-build/)
|
||
|
||
[Android.bp及其工具链](http://note.qidong.name/2017/08/android-blueprint/)
|
||
|
||
[Android Soong build系统介绍](https://www.jianshu.com/p/80013a768a45) |