10 KiB
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里,用来让用户选择编译设备与编译类型。其执行步骤如下:
-
定义变量answer(用以代表用户的选择),如果命令里给了参数则直接使用给定的参数,否则列出所有的编译选项让用户选项。
-
定义变量selection(用以代表变量answer所对应的字符串),如果用户没选择则使用默认选项aosp_arm-eng,如果用户输入的是数字则使用该数字对应的字符串,如果用户输入的是字符串则直接使用该字符串。
-
定义变量product,将selection里"-"的前面部分放在变量product里,如编译openthos则其值为"openthos"。
-
定义变量variant,将selection里两个"-"之间的部分放在变量variant里,如编译openthos则其值为"x86_64"。
-
定义变量version,将seleciton里"-"之后的部分放在version里,如编译openthos则其值可能是"user"、"userdebug"或"eng"。eng适用于开发阶段,userdebug适用于调试阶段,user适用于最终发布阶段。
-
定义如下3个环境变量
export TARGET_PRODUCT=$product export TARGET_BUILD_VARIANT=$variant export TARGET_BUILD_TYPE=release
-
set_stuff_for_environment函数,设置一些环境变量。
-
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的流程:
-
runMakeProductConfig
在ui/build/make.go,用来配置编译参数。在这里可以看到[第一段输出](# 第一段输出) -
runSoongBootstrap
和runSoong
在ui/build/soong.go,分别运行的是./bootstrap.bash
和soong
两个命令。在这里可以看到[第二段输出](# 第二段输出)和[第三段输出](# 第三段输出)./bootstrap.bash
的最后一句会执行build/blueprint/bootstrap.bash $@
,如不带参数则生成minibp,如带参数则生成一个基于Blueprint的构建系统。 -
runKati
在ui/build/kati.go,运行的是ckati命令。把所有的Android.mk文件生成ninja文件。 -
createCombinedBuildNinjaFile
在ui/build/build.go,在out/combined-openthos_x86_64.ninja文件里用include关键字把前两步生成的ninja文件包含进来。 -
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
是否都安装齐全。另:从这里是看不出来问题在哪的,要从往前翻,找到真正错误的地方。