分类: Android平台
2015-02-03 16:38:59
先从最先的mk这个文件说起。这个mk文件其实是perl脚本,不要被这个陌生的名字吓着,比起makefile还是好理解了很多。我刚看脚本时也不懂,也是一步步google,google是最好的老师嘛。
my $DEBUG = 1; # enable/disable script debugging message 这边其实打印的debug信息也不多,往下仔细看一下,就清楚了。
@chkDirs = qw(mediatek mediatek/config mediatek/build/tools);其实这个perl的数组。后面还会出现很多这样的数组。
后面的代码大部分是检验文件存不存在和赋值这类的,所以先忽略吧,这进入比较关键的make过程吧
$cmdArg = "CMD_ARGU=\"@mOpts\"";
$makeCmd = "make -f mediatek/build/makemtk.mk $cmdArg @mOpts";
以下的执行分为两种情况,
(1):new 这边将进行用户代码的复制,复制的文件是根据projectconfig.mk来复制。这个后面再稍微详细说吧
(2):remake 不复制用户工程配置的代码。如果编译内核会从新生成mediatek-config文件,其实如果重复编译的话。如果没有改到项目的配置。不用新生成这个文件也可以的。这个也后面再说吧。
if ($#arguments < 0)
{
print "you yan here6666666666666\n";
if (${uAct} =~ /(new|remake|clean)/)
{
if ($uAct =~ /(new|remake)/)
{
&chkMustEnv;
&chkDep;
}
$result += &p_system("$makeCmd ${uAct}all");
}
else
{
$result += &p_system("$makeCmd $uAct CUR_MODULE=android");
}
}
else
{
print "you yan here77777777777\n";
foreach $uMod (@arguments)
{
&chkDep("$uMod");
if ( ($KMOD_PATH ne "") && ($uMod eq "kernel") )
{
print "you yan here888888888\n";
print "$uAct $uMod $KMOD_PATH\n";
$result += &p_system("$makeCmd $uAct CUR_MODULE=$uMod KMOD_PATH=$KMOD_PATH");
last;
}
elsif ( ($DR_MODULE ne "") && ($uMod eq "android") )
{
$result += &p_system("$makeCmd $uAct CUR_MODULE=$uMod DR_MODULE=$DR_MODULE");
last;
}
else
{
$result += &p_system("$makeCmd $uAct CUR_MODULE=$uMod");
}
}
}
关于p_system这个函数就是调用perl的运行函数。
sub p_system
{
my ($cmd) = @_;
my ($debugp) = 0;
my $result;
($debugp != 0) && print("$cmd\n");
($performanceChk == 1) && print &CurrTimeStr . " system $cmd\n";
$result = system("$cmd");
($performanceChk == 1) && print &CurrTimeStr . " exit $cmd\n";
return $result;
}
真正的执行在system("$cmd");如果大家有空可以google一下,看看怎么回事。毕竟自己亲手弄弄比较好理解。
我们现在来看make -f mediatek/build/makemtk.mk吧
现在就进入了这个熟悉而又陌生,厌恶的世界了。其实比较不好看懂的也是在这边。如果大家想了解了叫makefile 和make的,给大家推荐两个文档——《跟我一起写makefile》和《gnu make》,其中《跟我一起写makefile》很适合入门,《gnu make》是跟很好的资料书,大部分makefile的知识点都用,很方便查找。在makefile中,比较经常需要查找的就是几个自动变量。如果你的脑袋觉得比较轻松的时候,可以记记,毕竟每次查一下还是要花时间的。
下面是一些自动变量,我先列出来
$@
代表规则中的目标文件名。如果目标是一个文档(Linux中,一般称.a文件为文档),那么它代表这个文档的文件名。在多目标的模式规则中,它代表的是哪个触发规则被执行的目标文件名。
$%
规则的目标文件是一个静态库文件时,代表静态库的一个成员名。例如,规则的目标是“foo.a(bar.o)”,那么,“$%”的值就为“bar.o”,“$@”的值为“foo.a”。如果目标不是函数库文件,其值为空。
$<
规则的第一个依赖文件名。如果是隐含规则,则它代表通过目标指定的第一个依赖文件。
$?
所有比目标文件更新的依赖文件列表,空格分割。如果目标是静态库文件名,代表的是库成员(.o文件)的更新情况
$^
规则的所有依赖文件列表,使用空格分隔。如果目标是静态库文件名,它所代表的只能是所有库成员(.o文件)名。一个文件可重复的出现在目标的依赖中,变量“$^”只记录它的一次引用情况。就是说变量“$^”会去掉重复的依赖文件。
$+
类似“$^”,但是它保留了依赖文件中重复出现的文件。主要用在程序链接时,库的交叉引用场合。
$*
在模式规则和静态模式规则中,代表“茎”。“茎”是目标模式中“%”所代表的部分
“$$@”、“$$(@D)”和“$$(@F)”(注意:要使用“$$”),它们分别代表了“目标完整的文件名”、“目标文件名中的目录部分”和“目标的实际文件名部分”。
makemtk.mk里将声明很多的变量,包括编译的线程,指定分区的文件
如果编译的选项是new的话将会复制客户的代码与配置文件,将会执行以下代码
custgen:
$(hide) echo $(SHOWTIME) $@ing...
$(hide) echo -e \\t\\t\\t\\b\\b\\b\\bLOG: $(S_LOG)$@.log
$(hide) make -f mediatek/build/custgen.mk $(DEAL_STDOUT_CUSTGEN) && \
$(SHOWRSLT) $${PIPESTATUS[0]} $(LOG)$@.log || $(SHOWRSLT) $${PIPESTATUS[0]} $(LOG)$@.log
其中hide := @,所以$(hide)即@,由于在makefile中执行每条指令都会打印出来,然而如果makefile中在命令前面在@,表示在执行这条语句是省略打印命令命令接下来我们来看make -f mediatek/build/custgen.mk,custgen.mk文件里面的内容很少,
include mediatek/build/Makefile
$(call codebase-path)
all: mtk-config-files mtk-custom-files
@echo "done"
mtk-config-files := $(strip $(call mtk.config.generate-rules,mtk-config-files))
mtk-custom-files := $(strip $(call mtk.custom.generate-rules,mtk-custom-files))
其中mtk-config-files和mtk-custom-files就是来搬运客户的配置文件和客户的配置源文件。mtk.config.generate-rules,mtk-config-files和mtk.custom.generate-rules,mtk-custom-files这两个宏的定义比较复杂,它们的实现分别在mediatek/build/libs/config.mk和mediatek/build/libs/custom.mk中。
大家在编译new的时候会看到类似的打印信息
[CONFIG] copy mediatek/config/公司产品目录/mtk_omx_core.cfg
to mediatek/config/out/公司产品目录/mtk_omx_core.cfg
这个是由mtk.config.generate-rules,mtk-config-files实现
[CUSTOM] copy mediatek/custom/公司产品目录/uboot/inc/cust_battery.h
to mediatek/custom/out/公司产品目录/uboot/inc/cust_battery.h
这个是由mtk.custom.generate-rules,mtk-custom-files实现。
将会分别把代码复制到mediatek/config/out和mediatek/custom/out这两个目录里,然而这部分代码是根据什么复制过来的呢,这边的代码就是会根据我们经常配的projectconfig.mk这个来执行,复制对应文件夹。后面再会说到编译过程。
下面来说我最关心的地方,kernel的配置。刚拿到MTK的代码时,我也是非常的蒙
也许做过MTK的future phone的同事,也许是不会蒙,可我真是蒙的,那是真实灰常的郁闷,呵呵。后面就有一定要把MTK的代码还原成真实android的想法。也可以再进步进步我的makefile。塞翁失马焉知非福嘛。后面再网上也看到有人说。做MTK的东西学不到什么,做MTK的android还是在future phone。我想当这个人,如果把MTK的脚本makefile都大概知道了,他也就不会说这句话了。如果要理清MTK的代码,你就必须对linux代码结构,编译,链接的方式有所了解。(我还真实花时间去看了linux的编译,呵呵,给大家推荐个文档《linux 内核构建系统》)。所以如果你理清了MTK的代码,你对linux的认识又会上一个小台阶。还有一些linux的书籍,就大家去google吧。
好吧,不扯了。各有各的想法吧。下面来看看如果编译内核的吧。
编译内核将运行makemtk.mk这个文件里的的
kernel:
ifeq ($(BUILD_KERNEL),yes)
ifeq ($(ACTION),)
$(hide) perl $(MEM_PARTITION_GENERATOR) \
$(MTK_PLATFORM) \
$(MTK_LCA_SUPPORT) \
$(MEM_PARTITION_TABLE) \
$(PARTITION_HEADER_LOCATION) \
$(dir $(SCATTER_FILE)) \
$(MTK_NAND_PAGE_SIZE) \
$(MTK_EMMC_SUPPORT) \
$(EMMC_CHIP) \
$(BOARDCONFIG_LOCATION) \
$(MTK_LDVT_SUPPORT) \
$(TARGET_BUILD_VARIANT) \
$(DEAL_STDOUT_PTGEN)
$(hide) perl $(OTA_SCATTER_GENERATOR) $(SCATTER_FILE) $(OTA_SCATTER_FILE)
endif
ifneq ($(KMOD_PATH),)
$(hide) echo building kernel module KMOD_PATH=$(KMOD_PATH)
$(hide) cd $(KERNEL_WD) && \
(KMOD_PATH=$(KMOD_PATH) ./build.sh $(ACTION) $(KERNEL_ARG) ) && cd $(MKTOPDIR)
else
$(hide) echo $(SHOWTIME) $(SHOWBUILD)ing $@...
$(hide) echo -e \\t\\t\\t\\b\\b\\b\\bLOG: $(S_MODULE_LOG)
$(hide) cd $(KERNEL_WD) && \
(MAKEJOBS=$(MAKEJOBS) ./build.sh $(ACTION) $(PROJECT) $(DEAL_STDOUT) && \
cd $(MKTOPDIR) && \
$(call chkImgSize,$(ACTION),$(PROJECT),$(SCATTER_FILE),$(if $(strip $(ACTION)),,$(KERNEL_IMAGES)),$(DEAL_STDOUT),&&) \
$(SHOWRSLT) $${PIPESTATUS[0]} $(MODULE_LOG) $(ACTION) || \
$(SHOWRSLT) $${PIPESTATUS[0]} $(MODULE_LOG) $(ACTION))
# $(hide) $(SHOWTIMECMD)
endif
else
$(hide) echo Not support $@.
endif
其中最重要的是在
$(hide) echo building kernel module KMOD_PATH=$(KMOD_PATH)
$(hide) cd $(KERNEL_WD) && \
(KMOD_PATH=$(KMOD_PATH) ./build.sh $(ACTION) $(KERNEL_ARG) ) && cd $(MKTOPDIR)
以上代码的功能是进入内核目录,执行build.sh这个shell脚本。MTK的脚本为什么要从perl到makefile再到shell。具体原因不太清楚,我猜是,跟它分区的文件这些有关。还望有哪个大哥指点指点。下面我们进入build.sh这个文件吧
这个文件比较重要的是
# select correct configuration file
make mediatek-configs
# update configuration
nice make ${makeflags} ${makedefs} silentoldconfig
先来说说,linux标准的kconfig文件吧。最重要的kconfig文件是在kernel/arch/arm/这个文件夹下
source "net/Kconfig"
source "drivers/Kconfig"
source "fs/Kconfig"
source "arch/arm/Kconfig.debug"
source "security/Kconfig"
source "crypto/Kconfig"
source "lib/Kconfig"
source "../mediatek/source/kernel/Kconfig"
这边也就跟mediatek这个文件夹联系起来了。另
在/mediatek/source/kernel/Kconfig的最后
source "../mediatek/platform/mt6575/kernel/Kconfig/Kernel"
source "../mediatek/platform/mt6575/kernel/Kconfig/Board"
source "../mediatek/platform/mt6575/kernel/Kconfig/Drivers"
也就把MTK跟linux有关的大部分配置选项包括进来的,呵呵,还有些是没有配置文件的,直接设置obj-y的,等会会看到。
接下来我们看makefile文件,最重要的makefile文件是在kernel/arch/arm/这个文件夹下
其中里面一句很重要的
include ../mediatek/build/kernel/Makefile
在mediatek/build/kernel/Makefile这个文件里,有段我们做驱动很关心的:
generated_files := $(call mtk.config.generate-rules)
.config mediatek-configs: $(MTK_ROOT_GEN_CONFIG)/kconfig $(MTK_ROOT_GEN_CONFIG)
@echo "[COPY] $< --> $@"
@cp $< $@
@echo "[COPY] $< --> .config"
@cp $< .config
大家在编译内核的时候会看到
**** Configuring / ..//mediatek/config/out/公司产品目录/autoconfig/kconfig / ****
[COPY] ../mediatek/config/out/公司产品目录/autoconfig/kconfig --> mediatek-configs
[COPY] ../mediatek/config/out/公司产品目录/autoconfig/kconfig --> .config
这边就是生成在kernel目录下的mediatek-cofigs这个文件的。这里面就是用到了,我前面说到的自动变量,如果大家忘记了,麻烦大家倒回去查一下吧。
由上面可以看出,mediatek-configs是mediatek/config/out/公司产品目录/autoconfig/kconfig的拷贝,这个kconfig不是linux的标准的kconfig,而是编译选项。而大家也会看到,这边也生成了一个.config,然而等你编译完,用mediatek-configs和.config比较一下,两个文件的内容是不一样的。具体原因是在执行make mediatek-config的时候也会生成一个.config文件,此时会把这段代码生成的覆盖。然而大家又会觉得疑惑,那mediatek/config/out/公司产品目录/autoconfig/kconfi是怎么生成的呢,在MTK的代码中是找不到跟这个文件一样的,这个文件是由三个文件合并而成。合并的代码在mediatek/build/libs/config.mk中
define .mtk.config.generate-auto-merge-rules
.PHONY: mediatek-configs.$(1)
mediatek-configs: mediatek-configs.$(1)
mediatek-configs.$(1): $(2)
$(2): PRIVATE_FILE_LIST := $(3)
$(2): $(3) $(4)
@echo "[CONFIG] generate $(2) "
@cat $(3) | $(5) > $(2)
Endef
大家在new的时候会看到
[CONFIG] generate mediatek/config/out/公司产品目录/autoconfig/kconfig
这句其实就是上段代码打印。
这个kconfig是由
mediatek/config/mt6575/autoconfig/kconfig/platform
mediatek/config/common/autoconfig/kconfig/AEE
mediatek/config/公司产品目录/autoconfig/kconfig/project
这三个文件合成的,使用的工具是
python mediatek/build/tools/config/merge-kconfig.py
如果大家想了解,可以再上段代码中,打印出来。
另:我们经常配置的projectconfig.mk这个文件,只是普通makefile声明的变量而已,并没有跟linux标准的kconfig和makefile联系。
由于时间限制,我现在只看到这里。Google那部分代码,有空再整理,本文写得比较粗糙和匆忙。由于表达能力不是很强,可能会有很多的语句不顺。望各位见谅。就仅当笔记。各位有什么意见和建议,欢饮指点哦。谢谢!