linux内核学习粗略kbuild Makefile编译流程

转自:http://gisyhy.blog.163.com/blog/static/1293903432010111591845942/

今天看Makefile文件,我头大了,此Makefile非彼Makefile,里面多了很多内置命令,比如origin、patsubst等等啦,这些都没听说过,更可恶的是,连网上都没有,可见,这是一件多么伤人的事情,分析这样的,真是让人折寿啊!没办法,大半天都没找出个头绪来,于是我也没什么办法了,只好利用跟踪的分析方法,就是按照安装的步骤来,通过make命令来找到突破口。这种方法的确好使。没用多久,我就稍微有了点头绪,也算今天没白白浪费掉。


先来个“make menuconfig”,这个内核编译的第一步,配置内核。因此我打开Makefile文件,查找目标--menuconfig,我操,怎么会没有,这是算是一个坎吧,怎么办呢,得想法子啊,我操,那换个,"config",我日啊,找了好长时间,发现有两个目标,很不容易。
config: scripts_basic outputmakefile FORCE
    $(Q)mkdir -p include/linux include/config
    $(Q)$(MAKE) $(build)=scripts/kconfig $@

%config: scripts_basic outputmakefile FORCE
    $(Q)mkdir -p include/linux include/config
    $(Q)$(MAKE) $(build)=scripts/kconfig $@


“%config”这是什么,没错,有点常识的都知道,一个匹配而已,真的算运气到位啊。如果是第一次执行这个肯定会找目标“script_basic”,在哪里,同样查找一下。
PHONY += scripts_basic
scripts_basic:
    $(Q)$(MAKE) $(build)=scripts/basic
    $(Q)rm -f .tmp_quiet_recordmcount


这个目标没有依赖关系,那么肯定每次都得执行一遍,来了,“$(Q)”是什么,查找。
ifeq ($(KBUILD_VERBOSE),1)
  quiet =
  Q =
else
  quiet=quiet_
  Q = @
endif


看到没有,其实就是为空或者"@",如果熟悉Makefile语法就知道,在指令前加上它,表示执行时,不打印这条命令,当然你可以
"make -s",就是不打印命令,但是这个会将所有的命令都屏蔽掉,想灵活一点就用“@”。

继续回到script_basic,“$(MAKE)”,放心,MAKE不是Makefile里面的变量了,是make命令内置的环境变量,就是"make"。重点来了,“$(build)”,这个就很难找了,如果没有一些时间,真的很难发现它究竟在哪里。讨论到这里我得说说Makefile的执行过程了,其实网上一大堆。

1、读取工作目录下的默认makefile文件(makefile,Makefile) (开始读我们的写的makefile主文件了)
2、依次读取工作目录makefile文件中使用指示符"include"包含的文件 (makefile主文件中包含的其他文件也读进来了)
3、查找重建所有已读取的makefile文件的规则(如果存在一个目标是当前读取的某一个makefile文件,则执行此规则重建此makefile文件, 完成以后从第一步开始重新执行) (makefile主文件极其包含的makefile文件有需要动态修改的,先修改在重新读进来)
4、初始化变量值并展开那些需要立即展开的变量和函数并根据预设条件确定执行分支 (相当于预处理过程吧?)
5、根据"终极目标"以及其他目标的依赖关系建立依赖关系链表 (开始整理我们的写的规则准备执行了,相当于编译链接过程)
6、执行除"终极目标"以外的所有的目标的规则(规则中如果所依赖的文件中一个时间戳比目标文件新,则根据规则所定义的命令重新创建目标) (最后两步就是执行了)
7、执行"终极目标"所在的规则 

有点多,但是建议还是看看。Makefile里面还可以包含其它文件,首先就会将其它文件的内容给填进来合在一起。一般会用关键字
"inlclude"来包含,和C程序类似。于是找找,关注所有在“$(build)”上边的包含文件吧,你将会发现。

include   $(srctree)/scripts/Kbuild.include

但是这里的“$(srctree)”,查找一下。

srctree        := $(if $(KBUILD_SRC),$(KBUILD_SRC),$(CURDIR))

注意:查找的时候,应该在查找行之上查找,毕竟肯定出现在这行之前嘛,这不是废话吗,但是会有人不注意的, linux内核学习(7)粗略走走kbuild Makefile编译流程 - 小鱼 - ringk--linuxer
我靠,这样搞来搞去,出现的不认识的更多啊,不要紧的,事情总在前进,我们总会想到法子的。首先看“$(KBUILD_SRC)”,继续查找,

# KBUILD_SRC is set on invocation of make in OBJ directory
# KBUILD_SRC is not intended to be used by the regular user (for now)
ifeq ($(KBUILD_SRC),)


这是最开始的一行,显然这个变量不是Makefile里的,那么还会是哪里的呢,还有一种情况就make KBUILD_SRC=XX menuconfig
其实这个也是我的估测,但是我非常有把握的。因为很有可能在srctree前,会给它赋值,既然这里有个ifeq,就是如果相等的意思,这个恐怕每个人都知道。

ifeq ($(KBUILD_SRC),)
。。。。。。
ifneq ($(KBUILD_OUTPUT),)
。。。。。
sub-make: FORCE
    $(if $(KBUILD_VERBOSE:1=),@)$(MAKE) -C $(KBUILD_OUTPUT) \
    KBUILD_SRC=$(CURDIR) \
    KBUILD_EXTMOD="$(KBUILD_EXTMOD)" -f $(CURDIR)/Makefile \
    $(filter-out _all sub-make,$(MAKECMDGOALS))
。。。。。
endif # ifneq ($(KBUILD_OUTPUT),)
endif # ifeq ($(KBUILD_SRC),)
。。。。。
srctree        := $(if $(KBUILD_SRC),$(KBUILD_SRC),$(CURDIR))


中间省略了一些,果真有,红色的注意一下,但是分析一下会发现,不会执行的,因为注意到还有个变量没有“$(KBUILD_OUTPUT)”,这个变量和“KBUILD_SRC”差不多,都是传进来的,其实我们可在文档中找到它的解释,
Documentation/kbuild/kbuld.txt,如是说:

KBUILD_OUTPUT
--------------------------------------------------
Specify the output directory when building the kernel.
The output directory can also be specified using "O=...".
Setting "O=..." takes precedence over KBUILD_OUTPUT.

其实就是定义了一个外部的目录。

好了,绕了这么大一圈回到:

srctree        := $(if $(KBUILD_SRC),$(KBUILD_SRC),$(CURDIR))

那么还得解释里面那个if是怎么回事啊,其实不要怎么解释,我的理解就是。
if  (KBUILD_SRC==空)
      KBUILD_SRC=$(KBUILD_SRC);
else
      KBUILD_SRC=$(CURDIR)
也就是说这里的srctree=$(CURDIR),那么后面那个又是什么,哇塞,这种分析够烦的。有的考察我们知识面了,我们可能又想到说在去里面找找,我们发现它和之前那个KBUILD_SRC差不多的,我们要采取特殊手法也就是排除法,我们自己写个Makefile来测试这个变量即可,和之前那个“$(MAKE)”其实是一样的,这也是我确定KBUILD_SRC肯定不是make内置的环境变量的理由。不知道就直接写个命令测试,很简单的。顾名思义嘛,就是当前目录,即源代码的顶级目录。所以嘛,srctree意思翻译过来就是源代码树,就是树的根目录嘛。那么我们再次回到。
include   $(srctree)/scripts/Kbuild.include
打开这个Kbuild.include文件查找build变量。
build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj

看到赋值了吧,这里又出现KBUILD_SRC,还是为空,那么build=-f $(srctree)/scripts/Makefile.build obj。这里有个“-f”选项,
make  help 看看-f选项是什么意思。这里就不说了,带回去。

scripts_basic:
    $(Q)make -f $(srctree)/scripts/Makefile.build obj=
scripts/basic
    $(Q)rm -f .tmp_quiet_recordmcount

意思现在还蛮明显的,就是利用Makefile.build脚本,这里既然涉及到kbuild的问题,我们先放放,里面是什么还没看。但是我们可以知道就是处理一下scripts/basic目录里面的一些文件而已,估计后面会用得着。回到%config:,看后面的那个目标“outputmakefile”。

outputmakefile:
ifneq ($(KBUILD_SRC),)
    $(Q)ln -fsn $(srctree) source
    $(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile \
        $(srctree) $(objtree) $(VERSION) $(PATCHLEVEL)
endif


可以自己试着分析一下。继续啊。

%config: scripts_basic outputmakefile FORCE
    $(Q)mkdir -p include/linux include/config
    $(Q)$(MAKE) $(build)=scripts/kconfig $@


还有个mkdir -p,呵呵,就是创建个目录嘛(如果没有)。后面重点来了。翻译一下。"$@"这个符号不用多说吧,就是目标menuconfig。

$(Q)make  -f  $(srctree)/scripts/Makefile.build obj= scripts/kconfig menuconfig

显然了,估计就是靠scripts/kconfig里面的文件来处理,然后制作出一个菜单界面来供用户选择,然后将配置参数存入.config文件中。好像不怎么复杂,呵呵,如果要仔细分析形成过程,又得花上很长时间的。不过我们知道这样一个过程即可。毕竟这不是重点嘛!

好了,“make menuconfig”这个命令就说到这儿吧!按照这种方法分析后面的估计就会简单些,希望如此。还是得感谢网络,很多知识点都有。时间不早了,寝室要熄灯了,哇!真够累的!明天可能有点事情。。linux内核学习(7)粗略走走kbuild Makefile编译流程 - 小鱼 - ringk--linuxer


结合:http://www.360doc.com/content/12/0103/19/6828497_177031793.shtml


你可能感兴趣的:(linux)