内核arch/arm/boot/Makefile阅读

本文深入讲解Makefile中的规则构成及工作原理,通过实例演示如何利用Makefile自动化编译流程。

 

root@ubuntu:/usr/src/linux-headers-2.6.32-26/arch/arm/boot# cat Makefile

#

# arch/arm/boot/Makefile

#

# This file is included by the global makefile so that you can add your own

# architecture-specific flags and dependencies.

#

# This file is subject to the terms and conditions of the GNU General Public

# License.  See the file "COPYING" in the main directory of this archive

# for more details.

#

# Copyright (C) 1995-2002 Russell King

#

 

MKIMAGE         := $(srctree)/scripts/mkuboot.sh

 

ifneq ($(MACHINE),)

include $(srctree)/$(MACHINE)/Makefile.boot

endif

 

# Note: the following conditions must always be true:

#   ZRELADDR == virt_to_phys(PAGE_OFFSET + TEXT_OFFSET)

#   PARAMS_PHYS must be within 4MB of ZRELADDR

#   INITRD_PHYS must be in RAM

ZRELADDR    := $(zreladdr-y)

PARAMS_PHYS := $(params_phys-y)

INITRD_PHYS := $(initrd_phys-y)

 

export ZRELADDR INITRD_PHYS PARAMS_PHYS

 

targets := Image zImage xipImage bootpImage uImage  #规则的目标,好几个啊。

 

ifeq ($(CONFIG_XIP_KERNEL),y)

 

$(obj)/xipImage: vmlinux FORCE

$(call if_changed,objcopy)

@echo '  Kernel: $@ is ready (physical address: $(CONFIG_XIP_PHYS_ADDR))'

 

$(obj)/Image $(obj)/zImage: FORCE

@echo 'Kernel configured for XIP (CONFIG_XIP_KERNEL=y)'

@echo 'Only the xipImage target is available in this case'

@false

 

else

 

$(obj)/xipImage: FORCE

@echo 'Kernel not configured for XIP (CONFIG_XIP_KERNEL!=y)'

@false

 

$(obj)/Image: vmlinux FORCE

$(call if_changed,objcopy)

@echo '  Kernel: $@ is ready'

 

$(obj)/compressed/vmlinux: $(obj)/Image FORCE

$(Q)$(MAKE) $(build)=$(obj)/compressed $@

 

$(obj)/zImage: $(obj)/compressed/vmlinux FORCE

$(call if_changed,objcopy)

@echo '  Kernel: $@ is ready'

 

endif

 

quiet_cmd_uimage = UIMAGE  $@

      cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A arm -O linux -T kernel /

  -C none -a $(LOADADDR) -e $(STARTADDR) /

  -n 'Linux-$(KERNELRELEASE)' -d $< $@

 

ifeq ($(CONFIG_ZBOOT_ROM),y)

$(obj)/uImage: LOADADDR=$(CONFIG_ZBOOT_ROM_TEXT)

else

$(obj)/uImage: LOADADDR=$(ZRELADDR)

endif

 

ifeq ($(CONFIG_THUMB2_KERNEL),y)

# Set bit 0 to 1 so that "mov pc, rx" switches to Thumb-2 mode

$(obj)/uImage: STARTADDR=$(shell echo $(LOADADDR) | sed -e "s/.$$/1/")

else

$(obj)/uImage: STARTADDR=$(LOADADDR)

endif

 

$(obj)/uImage: $(obj)/zImage FORCE

$(call if_changed,uimage)

@echo '  Image $@ is ready'

 

$(obj)/bootp/bootp: $(obj)/zImage initrd FORCE

$(Q)$(MAKE) $(build)=$(obj)/bootp $@

@:

 

$(obj)/bootpImage: $(obj)/bootp/bootp FORCE

$(call if_changed,objcopy)

@echo '  Kernel: $@ is ready'

 

PHONY += initrd FORCE

initrd:

@test "$(INITRD_PHYS)" != "" || /

(echo This machine does not support INITRD; exit -1)

@test "$(INITRD)" != "" || /

(echo You must specify INITRD; exit -1)

 

install: $(obj)/Image

$(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) /

$(obj)/Image System.map "$(INSTALL_PATH)"

 

zinstall: $(obj)/zImage

$(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) /

$(obj)/zImage System.map "$(INSTALL_PATH)"

 

zi:

$(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) /

$(obj)/zImage System.map "$(INSTALL_PATH)"

 

i:

$(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) /

$(obj)/Image System.map "$(INSTALL_PATH)"

 

subdir-    := bootp compressed

 

 

==========================

参考》《GNU makefile 中文手册》

 

Makefile规则介绍 

一个简单的 Makefile 描述规则组成: 

TARGET... : PREREQUISITES... 

COMMAND 

... 

... 

target:规则的目标。通常是最后需要生成的文件名或者为了实现这个目的而必需

的中间过程文件名。可以是.o文件、也可以是最后的可执行程序的文件名等。另外,目

标也可以是一个make执行的动作的名称,如目标“clean” ,我们称这样的目标是“伪

目标”。参考4.6 Makefile伪目标 一节 

 

prerequisites:规则的依赖。生成规则目标所需要的文件名列表。通常一个目标依

赖于一个或者多个文件。 

 

command:规则的命令行。是规则所要执行的动作(任意的 shell 命令或者是可在

shell下执行的程序) 。它限定了 make执行这条规则时所需要的动作。 

一个规则可以有多个命令行,每一条命令占一行。

注意: 每一个命令行必须以[Tab]字符开始,[Tab]字符告诉 make 此行是一个命令行。make按照命令完成相应的动作。

这也是书写 Makefile 中容易产生,而且比较隐蔽的错误。 

 

命令就是在任何一个目标的依赖文件发生变化后重建目标的动作描述。一个目标可

以没有依赖而只有动作(指定的命令) 。比如Makefile 中的目标“clean” ,此目标没有

依赖,只有命令。它所定义的命令用来删除 make过程产生的中间文件(进行清理工作)。  

 

什么是规则?

在 Makefile 中“规则”就是描述在什么情况下、如何重建规则的目标文件,通常

规则中包括了目标的依赖关系(目标的依赖文件)和重建目标的命令

make执行重建目标的命令,来创建或者重建规则的目标(此目标文件也可以是触发这个规则的上一个

规则中的依赖文件)。 规则包含了文件之间的依赖关系和更新此规则目标所需要的命令。  

一个 Makefile 文件中通常还包含了除规则以外的很多东西(后续我们会一步一步

的展开)。一个最简单的Makefile 可能只包含规则。规则在有些 Makefile 中可能看起来

非常复杂,但是无论规则的书写是多么的复杂,它都符合规则的基本格式。 

make程序根据规则的依赖关系,决定是否执行规则所定义的命令的过程我们称之

为执行规则。 

 

=============================================
2.2 2.3 简单的示例 
本小节开始我们在第一小节中提到的例子。此例子由3个头文件和8个C文件组成。
我们将书写一个简单的Makefile,来描述如何创建最终的可执行文件“edit”,此可执行
文件依赖于8个C源文件和3个头文件。Makefile文件的内容如下: 
 
所有的.o文件既是依赖(相对于可执行程序edit)又是目标(相对于.c和.h文件)。
edit是第一个目标,也就是终极目标。
#sample Makefile 
##############################
#规则描述了“edit”的依赖关系,并定义了链接.o文件生成目标“edit”的命令; 
edit : main.o kbd.o command.o display.o /      #edit是我们最后所需要的可执行程序,.o文件也是所要得到的目标。
insert.o search.o files.o utils.o        #规则的 目标:依赖文件
cc -o edit main.o kbd.o command.o display.o / 
insert.o search.o files.o utils.o    #这一行是命令
#############################
main.o : main.c defs.h    #规则的 目标:依赖文件
 
cc -c main.c       #这一行是命令
kbd.o : kbd.c defs.h command.h      #规则的 目标:依赖文件
cc -c kbd.c     #这一行是命令
command.o : command.c defs.h command.h    #规则的 目标:依赖文件
cc -c command.c   #这一行是命令
display.o : display.c defs.h buffer.h   #规则的 目标:依赖文件
cc -c display.c       #这一行是命令
insert.o : insert.c defs.h buffer.h    #规则的 目标:依赖文件
cc -c insert.c      #这一行是命令
search.o : search.c defs.h buffer.h    #规则的 目标:依赖文件
  
cc -c search.c        #这一行是命令
files.o : files.c defs.h buffer.h command.h    #规则的 目标:依赖文件
cc -c files.c       #这一行是命令
utils.o : utils.c defs.h   #规则的 目标:依赖文件
cc -c utils.c      #这一行是命令
clean :     #目标clean
rm edit main.o kbd.o command.o display.o / 
insert.o search.o files.o utils.o     #这是命令。
 
首先书写时,可以将一个较长行使用反斜线(/)来分解为多行,这样可以使我们
的Makefile书写清晰、容易阅读理解。但需要注意:反斜线之后不能有空格(这也是大
家最容易犯的错误,错误比较隐蔽) 。我们推荐将一个长行分解为使用反斜线连接得多
个行的方式。在完成了这个Maekfile以后;需要创建可执行程序“edit”,所要做的就是
在包含此Makefile的目录(当然也在代码所在的目录)下输入命令“make”。删除已经
此目录下之前使用“make”生成的文件(包括那些中间过程的.o文件),也只需要输入
命令“make clean”就可以了。 
在这个Makefile中,我们的目标(target)就是可执行文件“edit”和那些.o文件
(main.o,kbd.o….) ;依赖(prerequisites)就是冒号后面的那些 .c 文件和 .h文件。
所有的.o文件既是依赖(相对于可执行程序edit)又是目标(相对于.c和.h文件)。命令
包括 “cc –c maic.c”、“cc –c kbd.c”…… 
当规则的目标是一个文件,在它的任何一个依赖文件被修改以后,在执行“make”
时这个目标文件将会被重新编译或者重新连接。当然,此目标的任何一个依赖文件如果
有必要则首先会被重新编译。在这个例子中,“edit”的依赖为8个.o文件;而“main.o”
的依赖文件为“main.c”和“defs.h” 。当“main.c”或者“defs.h”被修改以后,再次
执行“make”,“main.o”就会被更新(其它的.o文件不会被更新) ,同时“main.o” 的
更新将会导致“edit”被更新。 
在描述依赖关系行之下通常就是规则的命令行(存在一些些规则没有命令行) ,
令行定义了规则的动作(如何根据依赖文件来更新目标文件)
命令行必需以[Tab]键开始,以和Makefile其他行区别。就是说所有的命令行必需以[Tab] 字符开始,但并不是
所有的以[Tab]键出现行都是命令行。 但make程序会把出现在第一条规则之后的所有以
[Tab]字符开始的行都作为命令行来处理。 (记住:make程序本身并不关心命令是如何
工作的,对目标文件的更新需要你在规则描述中提供正确的命令。“make”程序所做的
就是当目标程序需要更新时执行规则所定义的命令)。 
目标“clean”不是一个文件,它仅仅代表执行一个动作的标识。正常情况下,不
需要执行这个规则所定义的动作,因此目标“clean”没有出现在其它任何规则的依赖
列表中。因此在执行make时,它所指定的动作不会被执行。除非在执行make时明确地
指定它。而且目标“clean”没有任何依赖文件,它只有一个目的,就是通过这个目标
名来执行它所定义的命令。Makefile中把那些没有任何依赖只有执行动作的目标称为
“伪目标” (phony targets) 。参考4.6 Makefile伪目标 一节。需要执行“clean”目标
所定义的命令,可在shell下输入:make clean。 
=======================
当在 shell 提示符下输入“make”命令以后。make读取当前目录下的 Makefile 文
件,并将 Makefile 文件中的第一个目标作为其执行的“终极目标” ,开始处理第一个规
则(终极目标所在的规则) 。在我们的例子中,第一个规则就是目标“edit”所在的规
则。规则描述了“edit”的依赖关系,并定义了链接.o文件生成目标“edit”的命令;  make
在执行这个规则所定义的命令之前,首先处理目标“edit”的所有的依赖文件(例子中
的那些.o文件)的更新规则(以这些.o文件为目标的规则)。对这些.o文件为目标的规
则处理有下列三种情况: 
1.  目标.o文件不存在,使用其描述规则创建它; 
2.  目标.o文件存在,目标.o文件所依赖的.c源文件、 .h文件中的任何一个比目标.o
文件“更新”(在上一次 make之后被修改)。则根据规则重新编译生成它; 
3.  目标.o文件存在,目标.o文件比它的任何一个依赖文件(的.c源文件、.h文件)
“更新”(它的依赖文件在上一次 make之后没有被修改),则什么也不做。 
这些.o 文件所在的规则之所以会被执行,是因为这些.o 文件出现在“终极目标”
的依赖列表中。在 Makefile 中一个规则的目标如果不是“终极目标”所依赖的(或者
“终极目标”的依赖文件所依赖的) ,那么这个规则将不会被执行,除非明确指定执行
这个规则(可以通过make的命令行指定重建目标,那么这个目标所在的规则就会被执
行,例如 “make clean”) 。在编译或者重新编译生成一个.o文件时,make同样会去
寻找它的依赖文件的重建规则(是这样一个规则:这个依赖文件在规则中作为目标出
现),在这里就是.c和.h文件的重建规则。在上例的Makefile中没有哪个规则的目标是.c
或者.h 文件,所以没有重建.c 和.h 文件的规则。不过 C 言语源程序文件可以使用工具
Bison或者 Yacc 来生成(具体用法可参考相应的手册) 。 
完成了对.o文件的创建(第一次编译)或者更新之后,make程序将处理终极目标
“edit”所在的规则,分为以下三种情况: 
1.  目标文件“edit”不存在,则执行规则以创建目标“edit”。 
2.  目标文件“edit”存在,其依赖文件中有一个或者多个文件比它“更新” ,则根
据规则重新链接生成“edit”。 
3.  目标文件“edit”存在,它比它的任何一个依赖文件都“更新”,则什么也不做。  
上例中,如果更改了源文件“insert.c”后执行make,“insert.o”将被更新,之后
终极目标“edit”将会被重生成;如果我们修改了头文件“command.h”之后运行“make”,
那么“kbd.o”、“command.o”和“files.o”将会被重新编译,之后同样终极目标“edit”
也将被重新生成。 
以上我们通过一个简单的例子,介绍了 Makefile 中目标和依赖的关系。我们简单
总结一下:对于一个 Makefile 文件,“make”首先解析终极目标所在的规则(上节例
子中的第一个规则),根据其依赖文件(例子中第一个规则的8个.o文件)依次(按照
依赖文件列表从左到右的顺序)寻找创建这些依赖文件的规则。首先为第一个依赖文件
(main.o)寻找创建规则,如果第一个依赖文件依赖于其它文件(main.c、defs.h),
则同样为这个依赖文件寻找创建规则(创建 main.c和 defs.h的规则,通常源文件和头
文件已经存在,也不存在重建它们的规则)……,直到为所有的依赖文件找到合适的创
建规则。之后 make 从最后一个规则(上例目标为 main.o 的规则)回退开始执行,最
终完成终极目标的第一个依赖文件的创建和更新。之后对第二个、第三个、第四个……
终极目标的依赖文件执行同样的过程(上例的的顺序是“main.o”、“kbd.o”、
“command.o”……)。 
创建或者更新每一个规则依赖文件的过程都是这样的一个过程(类似于 c 语言中的
递归过程) 。对于任意一个规则执行的过程都是按照依赖文件列表顺序,对于规则中的
每一个依赖文件,使用同样方式(按照同样的过程)去重建它,在完成对所有依赖文件
的重建之后,最后一步才是重建此规则的目标。 
更新(或者创建)终极目标的过程中,如果任何一个规则执行出现错误 make就立
即报错并退出。整个过程make只是负责执行规则,而对具体规则所描述的依赖关系的
正确性、规则所定义的命令的正确性不做任何判断。就是说,一个规则的依赖关系是否
正确、描述重建目标的规则命令行是否正确,make不做任何错误检查。 
因此,需要正确的编译一个工程。需要在提供给 make 程序的 Makefile 中来保证
其依赖关系的正确性、和执行命令的正确性。 

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

等风来不如迎风去

你的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值