xiaozhao-521 发表于 2013-1-26 12:39:37

makefile 基础知识

Makefile基础 :
 
make命令会自动读取当前目录下的Makefile文件,完成相应的编译步骤。Makefile由一组规则(Rule)组成,每条规则的格式是:
target ... : prerequisites ... command1command2... 
例如:
main: main.o stack.o maze.ogcc main.o stack.o maze.o -o main 
main是这条规则的目标(Target),main.o、stack.o和maze.o是这条规则的条件(Prerequisite)。
目标和条件之间的关系是:欲更新目标,必须首先更新它的所有条件;所有条件中只要有一个条件被更新了,目标也必须随之被更新。所谓“更新”就是执行一遍规则中的命令列表,命令列表中的每条命令必须以一个Tab开头,
注意不能是空格,Makefile的格式不像C语言的缩进那么随意,对于Makefile中的每个以Tab开头的命令,make会创建一个Shell进程去执行它。
 
通常Makefile都会有一个clean规则,用于清除编译过程中产生的二进制文件,保留源文件:
clean:@echo "cleanning project"-rm main *.o@echo "clean completed" 把这条规则添加到我们的Makefile末尾,然后执行这条规则:
$ make clean cleanning projectrm main *.oclean completed 如果在make的命令行中指定一个目标(例如clean),则更新这个目标,如果不指定目标则更新Makefile中第一条规则的目标(缺省目标)。
 
命令前面加@和-字符的效果:
        如果make执行的命令前面加了@字符,则不显示命令本身而只显示它的结果;
       通常make执行的命令如果出错(该命令的退出状态非0)就立刻终止,不再执行后续命令,但如果命令前面加了-号,即使这条命令出错,make也会继续执行后续命令。
通常rm命令和mkdir命令前面要加-号,因为rm要删除的文件可能不存在,mkdir要创建的目录可能已存在,这两个命令都有可能出错,但这种错误是应该忽略的。
 
     文件名则不一定是Makefile。事实上,执行make命令时,是按照GNUmakefile、makefile、Makefile的顺序找到第一个存在的文件并执行它,不过还是建议使用Makefile做文件名。除了GNU make,有些UNIX系统的make命令不是GNU make,不会查找GNUmakefile这个文件名,如果你写的Makefile包含GNU make的特殊语法,可以起名GNUmakefile,否则不建议用这个文件名。
 
隐含规则和模式规则:
make的隐含规则数据库可以用make -p命令打印,打印出来的格式也是Makefile的格式,包括很多变量和规则。
#号在Makefile中表示单行注释,就像C语言的//注释一样。CC是一个Makefile变量,用CC = cc定义和赋值,用$(CC)取它的值,其值应该是cc。
$@和$<是两个特殊的变量,$@的取值为规则中的目标,$<的取值为规则中的第一个条件。%.o: %.c是一种特殊的规则,称为模式规则(Pattern Rule)。
 
一个目标依赖于若干条件,现在换个角度,以条件为中心,Makefile还可以这么写:
main: main.o stack.o maze.ogcc main.o stack.o maze.o -o mainmain.o stack.o maze.o: main.hmain.o maze.o: maze.hmain.o stack.o: stack.hclean:-rm main *.o.PHONY: clean 
对于多目标的规则,make会拆成几条单目标的规则来处理,例如
target1 target2: prerequisite1 prerequisite2command $< -o $@ 
这样一条规则相当于:
target1: prerequisite1 prerequisite2command prerequisite1 -o target1target2: prerequisite1 prerequisite2command prerequisite1 -o target2 注意两条规则的命令列表是一样的,但$@的取值不同。
 
变量:
foo = $(bar) bar = Huh? all: @echo $(foo) 我们执行make将会打出Huh?。当make读到foo = $(bar)时,确定foo的值是$(bar),但并不立即展开$(bar),然后读到bar = Huh?,确定bar的值是Huh?,然后在执行规则all:的命令列表时才需要展开$(foo),得到$(bar),再展开$(bar),得到Huh?。因此,虽然bar的定义写在foo之后,$(foo)展开还是能够取到$(bar)的值。
 
有时候我们希望make在遇到变量定义时立即展开,可以用:=运算符,例如:
x := fooy := $(x) barall: @echo "-$(y)-" 运算符是?=,例如foo ?= $(bar)的意思是:如果foo没有定义过,那么?=相当于=,定义foo的值是$(bar),但不立即展开;如果先前已经定义了foo,则什么也不做,不会给foo重新赋值。
 
 
常用的特殊变量有:
 
$@,表示规则中的目标。
$<,表示规则中的第一个条件。
$?,表示规则中所有比目标新的条件,组成一个列表,以空格分隔。
$^,表示规则中的所有条件,组成一个列表,以空格分隔。
 
 
main: main.o stack.o maze.ogcc main.o stack.o maze.o -o mainv可以改写成:
main: main.o stack.o maze.ogcc $^ -o $@ 
常用的make命令行选项
-n选项只打印要执行的命令,而不会真的执行命令,这个选项有助于我们检查Makefile写得是否正确,由于Makefile不是顺序执行的,用这个选项可以先看看命令的执行顺序,确认无误了再真正执行命令。
-C选项可以切换到另一个目录执行那个目录下的Makefile,
在make命令行也可以用=或:=定义变量,如果这次编译我想加调试选项-g,但我不想每次编译都加-g选项,可以在命令行定义CFLAGS变量,而不必修改Makefile编译完了再改回来:
$ make CFLAGS=-gcc -g   -c -o main.o main.ccc -g   -c -o stack.o stack.ccc -g   -c -o maze.o maze.cgcc main.o stack.o maze.o -o main如果在Makefile中也定义了CFLAGS变量,则命令行的值覆盖Makefile中的值。
 
 
页: [1]
查看完整版本: makefile 基础知识