初步认识linux下的GNU的makefile文件编写

会不会写Makefile,从侧面说明一个人是否具备完成一个大型工程的能力,因为Makefile关系到整个工程的编译规则,当工程较小时,可以不需要Makefile编译,但是当工程较大时,一个工程有很多个不同的源文件,我们不可能一个个去编译,所以这个时候Makefile就是必不可少的了。

程序的编译和链接
在C,C++中,首先把源文件编译成中间目标文件,Windows下是 .obj文件,Unix和linux下是 .o文件,即object files,这个动作叫编译,把大量目标文件合成执行文件,叫链接。在编译时,编译器只检查函数语法,函数变量是否声明,若未声明,给出一个warning,但是可以生成object files,在链接程序时,链接器会在所有的object files中找寻函数的实现,如果没找到,则会报错。
什么是Makefile?
在linux命令行输入make命令时,需要一个makefile文件,以告诉make要怎么去编译和链接程序,实际上就是一个把程序编译和链接的步骤写入makefile,只需要make一下就可以编译整个工程,得到一个可执行文件,而不需要编译多个源文件。
写makefile时有哪些规则?
1)如果工程没有被编译过,那么所有的C文件都会被编译和链接
2)如果某几个C文件被修改,值编译被修改的文件,并链接目标文件
3)如果工程的头文件被修改了,需编译引用这个头文件的几个C程序,并链接目标程序
makefile的规则

target… : prerequisites….
command
….
….

target :是一个目标文件,可以是object file文件,也可以是执行文件,还可以是一个伪目标
prerequisites : 要生成target所需要的文件
command :生成目标文件需要执行的命令
这是一个依赖关系,就是说target目标文件的生成依赖于prerequisites的文件,生成规则在command中
注意:command行前面一定要有一个tab键
例如:一个工程中有两个.h文件,三个.c文件,Makefile如下
tar : add.o mul.o sup.o
cc -o add.o mul.o sup.o

add.o : add.c stdio.h
cc -c add.c
mul.o: mul.c fd.h
cc -c mul.c
sup.o: sup.c fd.h
cc -c sup.c
clean:
rm tar add.o mul.o sup.o

如果要删除目标文件和执行文件,只需有在命令行输入 make clean就可以了,这里需要说明的是。clean不是一个目标文件,而是一个动作名字,那么make不会自动去找文件的依赖性,也不会执行其后的命令,要执行clean ,必须要由make指出clean这个动作。
make是如何工作的
在默认的方式下,也就是我们只输入 make 命令。那么,
1、 make 会在当前目录下找名字叫“ Makefile”或“ makefile”的文件。
2、如果找到,它会找文件中的第一个目标文件( target),在上面的例子中,他会找到“ tar”这个文件,并把这个文件作为最终的目标文件。
3、如果 tar文件不存在,或是 tar 所依赖的后面的 .o 文件的文件修改时间要比 tar这个文件新,那么,他就会执行后面所定义的命令来生成 tar这个文件。
4、如果 tar 所依赖的.o 文件也存在,那么 make 会在当前文件中找目标为.o 文件的依赖性,如果找到则再根据那一个规则生成.o 文件。(这有点像一个堆栈的过程)
5、当然,你的 C 文件和 H 文件是存在的啦,于是 make 会生成 .o 文件,然后再用 .o文件生命 make 的终极任务,也就是执行文件 edit 了。
Makefile中可以使用变量,简化代码
声明一个变量objects,在makefile中以$(objects)来使用这个变量
之前的例子可以改为:
objects = add.o mul.o sup.o
tar : $(objects)

cc -o $(objects)

add.o : add.c stdio.h
cc -c add.c
mul.o: mul.c fd.h
cc -c mul.c
sup.o: sup.c fd.h
cc -c sup.c
clean :
rm tar $(objects)
于是如果有新的 .o 文件加入,我们只需简单地修改一下 objects 变量就可以了
make 自动推导的能力
GNU 的 make 很强大,它可以自动推导文件以及文件依赖关系后面的命令,make 会自动识别,并自己推导命令。
只要 make 看到一个[.o]文件,它就会自动的把[.c]文件加在依赖关系中,如果 make 找到一个 what.o,那么 what.c,就会是 what.o 的依赖文件。并且 cc -c what.c 也会被推导出来,于是,我们的 makefile 再也不用写得这么复杂。上面的例子又可以改为:
objects = add.o mul.o sup.o
edit : $(objects)

cc -o $(objects)

add.o : stdio.h
mul.o: fd.h
sup.o: fd.h
.PHONY : clean
clean :
rm edit $(objects)
这种方法,也就是 make 的“隐晦规则”。上面文件内容中,“ .PHONY”表示, clean 是个伪目标文件
规则中的通配符
如果我们想定义一系列比较类似的文件,我们很自然地就想起使用通配符。 make 支持三种通配符: *,?, […]。
通配符代替了你一系列的文件,如“ .c”表示所以后缀为 c 的文件。一个需要我们注意的是,如果我们的文件名中有通配符,如:“ ”,那么可以用转义字符“ \”,如“ *”来表示真实的“ *”字符,而不是任意长度的字符串。先来看一个例子吧:
clean:
rm -f *.o(即删除makefile中所有的.o文件)
查找文件的功能
在一些大的工程中,有大量的源文件,我们通常的做法是把这许多的源文件分类,并存放在不同的目录中。所以,当 make 需要去找寻文件的依赖关系时,你可以在文件前加上路径,但最好的方法是把一个路径告诉 make,让 make 在自动去找。Makefile 文件中的特殊变量“ VPATH”就是完成这个功能的,如果没有指明这个变量, make
只会在当前的目录中去找寻依赖文件和目标文件。如果定义了这个变量,那么, make 就会在当前目录找不到的情况下,到所指定的目录中去找寻文件了。
VPATH = src:../headers
上面的的定义指定两个目录,“ src”和“ ../headers”, make 会按照这个顺序进行搜索。目录由“冒号”分隔。(当然,当前目录永远是最高优先搜索的地方)
另一个设置文件搜索路径的方法是使用 make 的“ vpath”关键字(注意,它是全小写的),这不是变量,这是一个 make 的关键字,这和上面提到的那个 VPATH 变量很类似,但是它更为灵活。它可以指定不同的文件在不同的搜索目录中。这是一个很灵活的功能。它的使用
方法有三种:
1、 vpath 为符合模式的文件指定搜索目录。
2、 vpath 清除符合模式的文件的搜索目录。
3、 vpath清除所有已被设置好了的文件搜索目录。
vapth 使用方法中的需要包含“ %”字符。“ %”的意思是匹配零或若干字符,例如,
“ %.h”表示所有以“ .h”结尾的文件。 指定了要搜索的文件集,而则指定了的文件集的搜索的目录。例如:
vpath %.h ../headers该语句表示,要求 make 在“ ../headers”目录下搜索所有以“ .h”结尾的文件。(如果某文件在当前目录没有找到的话)
我们可以连续地使用 vpath 语句,以指定不同搜索策略。如果连续的 vpath 语句中出现了相同的,或是被重复了的,那么, make 会按照 vpath 语句的先后顺序来执行
搜索。如:
vpath %.c foo
vpath % b lish
vpath %.c bar
其表示“ .c”结尾的文件,先在“ foo”目录,然后是“ blish”,最后是“ bar”目录。
vpath %.c foo:bar
vpath % blish
而上面的语句则表示“ .c”结尾的文件,先在“ foo”目录,然后是“ bar”目录,最后才是“ blish”目录。
环境变量
make 运行时的系统环境变量可以在 make 开始运行时被载入到 Makefile 文件中,但是如果Makefile 中已定义了这个变量,或是这个变量由 make 命令行带入,那么系统的环境变量的值将被覆盖。(如果 make 指定了“ -e”参数,那么,系统环境变量将覆盖 Makefile 中定义的变量)因此,如果我们在环境变量中设置了“ CFLAGS”环境变量,那么我们就可以在所有的Makefile 中使用这个变量了。这对于我们使用统一的编译参数有比较大的好处。如果 Makefile中定义了 CFLAGS,那么则会使用 Makefile 中的这个变量,如果没有定义则使用系统环境变量的值,一个共性和个性的统一,很像“全局变量”和“局部变量”的特性。当 make 嵌套调用时,上层 Makefile 中定义的变量会以系统环境变量的方式传递到下层的 Makefile 中。当然,默认情况下,只有通过命令行设置的变量会被传递。而定义在文件中的变量,如果要向下层 Makefile 传递,则需要使用 exprot关键字来声明。当然,我并不推荐把许多的变量都定义在系统环境中,这样,在我们执行不用的 Makefile时,拥有的是同一套系统变量,这可能会带来更多的麻烦
自动化变量
所谓自动化变量,就是这种变量会把模式中所定义的一系列的文件自动地挨个取出,直至所有的符合模式的文件都取完了。这种自动化变量只应出现在规则的命令中。
下面给出几个常用的的自动化变量及其说明:
这里写图片描述
在makefile中用自动化变量代替文件,是程序简洁很多

makefile的规则还有很多很多,这里只是简单了总结了一些基本语法,学完后写一个不是很复杂的过程已经不是问题了,如果还感兴趣的话,建议大家可以去看看 陈皓老师写的 <跟我一起写 Makefile>,本文也主要总结于此作

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值