您的位置:首页 > 其它

Makefile基础

2015-12-23 19:10 267 查看
摘自:http://o0o0o0o.iteye.com/blog/1108171

Makefile基础 :

 

make命令会自动读取当前目录下的
Makefile
文件,完成相应的编译步骤。Makefile由一组规则(Rule)组成,每条规则的格式是:

Java代码  


target ... : prerequisites ...   

    command1  

    command2  

    ...  

 

例如:

Java代码  


main: main.o stack.o maze.o  

    gcc 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
规则,用于清除编译过程中产生的二进制文件,保留源文件:

Java代码  


clean:  

    @echo "cleanning project"  

    -rm main *.o  

    @echo "clean completed"  

 把这条规则添加到我们的Makefile末尾,然后执行这条规则:

Java代码  


$ make clean   

cleanning project  

rm main *.o  

clean 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还可以这么写:

Java代码  


main: main.o stack.o maze.o  

    gcc main.o stack.o maze.o -o main  

  

main.o stack.o maze.o: main.h  

main.o maze.o: maze.h  

main.o stack.o: stack.h  

  

clean:  

    -rm main *.o  

  

.PHONY: clean  

 

对于多目标的规则,
make
会拆成几条单目标的规则来处理,例如

Java代码  


target1 target2: prerequisite1 prerequisite2  

    command $< -o $@  

 

这样一条规则相当于:

Java代码  


target1: prerequisite1 prerequisite2  

    command prerequisite1 -o target1  

  

target2: prerequisite1 prerequisite2  

    command prerequisite1 -o target2  

 注意两条规则的命令列表是一样的,但
$@
的取值不同。

 

变量:

Java代码  


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
在遇到变量定义时立即展开,可以用
:=
运算符,例如:


Java代码  


x := foo  

y := $(x) bar  

  

all:   

    @echo "-$(y)-"  

 运算符是
?=
,例如
foo ?= $(bar)
的意思是:如果
foo
没有定义过,那么
?=
相当于
=
,定义
foo
的值是
$(bar)
,但不立即展开;如果先前已经定义了
foo
,则什么也不做,不会给
foo
重新赋值。


 

 

常用的特殊变量有:

 

$@
,表示规则中的目标。


$<
,表示规则中的第一个条件。


$?
,表示规则中所有比目标新的条件,组成一个列表,以空格分隔。


$^
,表示规则中的所有条件,组成一个列表,以空格分隔。


 

 

Java代码  


main: main.o stack.o maze.o  

    gcc main.o stack.o maze.o -o mainv  

可以改写成:

Java代码  


main: main.o stack.o maze.o  

    gcc $^ -o $@  

 

常用的
make
命令行选项


-n
选项只打印要执行的命令,而不会真的执行命令,这个选项有助于我们检查Makefile写得是否正确,由于Makefile不是顺序执行的,用这个选项可以先看看命令的执行顺序,确认无误了再真正执行命令。

-C选项可以切换到另一个目录执行那个目录下的Makefile,

make
命令行也可以用
=
:=
定义变量,如果这次编译我想加调试选项
-g
,但我不想每次编译都加
-g
选项,可以在命令行定义
CFLAGS
变量,而不必修改Makefile编译完了再改回来:
$ make CFLAGS=-g
cc -g   -c -o main.o main.c
cc -g   -c -o stack.o stack.c
cc -g   -c -o maze.o maze.c
gcc main.o stack.o maze.o -o main


如果在Makefile中也定义了
CFLAGS
变量,则命令行的值覆盖Makefile中的值。

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: