Linux环境下的Makefile学习

本次内容我们主要学习总结以下内容:make与Makefile介绍,Makefile基本规则,简单的Makefile编写,Make自动化变量,Makefile编译多个可执行文件等。再深入的将介绍make常用内嵌函数以及多级目录Makefile。

1.make与Makefile介绍

(1)make工具

利用make工具可以自动完成编译工作。这些工作包括:如果仅修改了某几个源文件,则只重新编译这几个源文件;如果某个头文件被修改了,则重新编译所包含该头文件的源文件。利用这种自动编译可大大简化开发工作,避免不必要的重新编译。

(2)Makefile

make工具通过一个称为Makefile的文件来完成并自动维护编译工作。Makefile文件描述了整个工程的编译、连接等规则。

2.Makefile基本规则

(1)目标(TARGET)程序产生的文件,如可执行文件和目标文件;目标也可以是要执行的动作,如clean,也称为伪目标。

(2)依赖(DEPENDENCIES)是用来产生目标的输入文件列表,一个目标通常依赖于多个文件。

(3)命令(COMMAND)是make执行的动作(命令是shell命令或是可在shell下执行的程序)。注意:每个命令行的起始字符必须为TAB字符

(4)如果DEPENDENCIES中有一个或多个文件更新的话,COMMAND就要执行,这就是Makefile最核心的内容。

3.简单的Makefile例子

(1)首先假设有如下几个源文件:main.c、add.c、add.h、sub.c、sub.h

(2)编写Makefile

此时,我们可以输入make命令,实现对源文件的编译等操作:

1)Makefile是基于更新时间来进行编译的,意思是说,当我第二次make命令时,Makefile会检查哪些源文件是在第一次make之后有更新的,然后对这些文件进行有选择的重新编译。

2)同样,如果我们明确知道自己刚刚更新的是哪一个源文件,也可以对更新的单一文件做make命令。例如我刚刚跟新了add.c,就可以只对依赖于add.c的文件进行make操作——make add.o。

3)留意到Makefile文件中最后两行clean开始的代码,执行make clean可以删除我们想要删除的文件。但是有一个问题,如果此时有一个同名为clean的源文件(类似于上一种情况),此时make clean误以为是重新编译clean源文件。

4)解决办法是,在Makefile文件开头添加.PHONY:clean

4.Makefile自动化变量
  • $@:规则的目标文件名
  • $<:规则的第一个依赖文件名
  • $^:规则的所有依赖文件列表

(1)同样,假设有如下几个源文件:main.c、add.c、add.h、sub.c、sub.h,使用自动变量编写如下Makefile文件:

其中OBJECTS是一个变量。

5.Makefile编译多个可执行文件
  • 模式规则:%.o:%.c
  • 后缀规则:.c.o:

(1)也可以不使用上述规则,系统将调用默认的规则。
(2)使用自动推导的功能(自动将变量下.c文件编译成.o文件)
all:$(BIN)
上面的代码可以实现编译多个可执行文件。(否则make只能编译一个可执行文件)
(3)还记得前面提到的gcc -c选项吗?(-c:通知gcc取消连接步骤,即编译源码并在最后生成目标文件)
最后一步由.o生成可执行文件时,不加此选项!(.c生成.o时可以加此选项)

(4)仔细思考如下Makefile文件:

1)对all:$(BIN)而言,首先all这个目标依赖于$(BIN),要生成all就得先生成$(BIN)。但是all是个伪目标,所以只需生成$(BIN)即可。

2)接着Makefile就会去生成$(BIN)里面的文件(01test, 02test, 03test),我们并没有给出这些文件是如何生成的。那么编译器将会自动推导:自动将同名的.c文件生成同名的可执行文件。

3)%.0:%.c是告诉编译器你要按照我自己的规则来将.c文件推导成.o文件。
4)此外,如果我们不想让编译器自动推导,那么我们就要自己编写目标文件的生成规则。例如:
01test:01test.o
$(CC) $(CFLAGS) $^ -o $@

6.make常用内嵌函数
  • 函数调用:$(function arguments)
  • $(wildcard PATTERN):当前目录下匹配模式的文件
    例如:src=$(wildcard *.c)    #匹配所有.c文件
  • $(patsubst PATTERN,REPLACEMENT, TEXT):模式替换函数
    例如:$(patsubst %.c, %.o, $src)
    等价于$(src:.c=.o)    #将变量src中所有.c文件替换为.o文件
  • shell函数:执行shell命令
    例如:$(shell ls -d */)    #匹配当前目录下的所有子目录,/不能忘记,否则将匹配当前目录下的所有文件。
7.多级目录Makefile

(1)前面介绍的示例都有一个共性:所有源文件都在一个目录下,那么如果main.c同级目录下还有其他子目录,并且子目录里有main.c依赖的源文件时,该怎么办呢?

这就需要更高级的Makefile编写了,考虑如下示例:(结合上面的函数仔细思考)

(2)上一个例子是将多个子目录下的各个源文件最终生成一个当前目录下可执行文件。那么考虑有没有这么一种情况:将各个子目录下的源文件各自生成一个可执行文件。该怎么实现呢?

最后附上:
陈浩“跟我一起写Makefile系列”:http://blog.csdn.net/haoel/article/details/2886/
gnu的make使用手册中文版下载地址:http://pan.baidu.com/s/1qYhicRa

发表评论

电子邮件地址不会被公开。 必填项已用*标注