Makefile学习1:基础部分(理解makefile是什么,目的作用是什么,基本规则是什么)

第一部分
一、名词
1.Make是一个解释Makefile的工具,而Makefile可以最大的作用是实现对工程的自动编译,只有掌握了编写Makefile的能力才能掌握完成大型工程的能力,因为一个大型工程往往是由许源文件组成的,这些源文件按照其功能,类型,模块放在了若干个文件,这些文件有编译的先后顺序,这些规则都必须通过Makefile来实现。

2.编译:源文件.c首先通过编译生成.o文件也就是obj文件这是生成可执行文件的第一个过程,也就是编译。而编译过程想要成功,需要的是语法的正确,函数与变量声明的正确,其中后者只需你告诉编译器头文件的位置(定义往往在.c声明在.h),所以只需要语法正确,编译器就能编译出.o中间文件。

3.链接:链接主要是链接函数和全局变量,这个步骤不会再去管源文件.c,因为源文件都被编译成了机器可以识别的二进制文件.o,然而一个源文件就会对应一个.o文件,这也意味着源文件越多.o文件就越多,而由于在链接时必须指明每一个.o文件导致编译链接过程变得十分繁琐,因此我们往往会给.o中间文件打个包,在windows下这种包文件称之为库文件.lib文件(Library file),在UNIX下,称之为是 Archive File,也就是 .a 文件。

总结:源文件首先会通过编译生成可执行文件,编译只会检查函数、变量是否声明,代码语法是否正确,如果函数未声明只会给出警告,但可以生成Object File。而在链接中,链接器会在所有的Object file中寻找函数的实现,如果找不到便会报错,因此链接时你需要指定Object File。

二、Makefile的规则
Target … : prerequisities…
Command

Target 指的是最终要生成的目标文件,可以是可执行文件也可以是中间文件,prerequisities指的是生成目标文件所需要的源文件或者是头文件或者是中间文件,而Command则是指make要执行的指令。
示例:假设一个工程有8个.c文件和3个.h文件,依据规则我们需要如下编写Makefile。
edit : main.o kbd.o command.o display.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 :
rm edit main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o

目标文件分为两部分,第一部分是.o文件,每个.o文件都有对应依赖即(.c与.h文件),而这些.o文件又是最终生成的可执行文件的依赖。

在定义好依赖关系之后,下一行编写生成目标文件的命令(Command)。
注意该行命令一定要以一个Tap键开始,在执行make指令之后,make解释器会先比较target与prerequisities的日期,如果prerequisities日期较新或者target没写,则会执行下一行的命令。

注:Clean: clean 不是一个文件,它只不过是一个动作名字,有点像 C 语言
中的 lable 一样,其冒号后什么也没有,那么,make 就不会自动去找文件的依赖性,也就
不会自动执行其后所定义的命令。要执行其后的命令,就要在 make 命令后明显得指出这个
lable 的名字,即我们经常使用的make clean

三、Make是如何工作的
在默认的方式下,也就是我们只输入 make 命令。那么,
1、make 会在当前目录下找名字叫“Makefile”或“makefile”的文件。
2、如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到
“edit”这个文件,并把这个文件作为最终的目标文件。
3、如果 edit 文件不存在,或是 edit 所依赖的后面的 .o 文件的文件修改时间要比 edit
这个文件新,那么,他就会执行后面所定义的命令来生成 edit 这个文件。
4、如果 edit 所依赖的.o 文件也不存在,那么 make 会在当前文件中找目标为.o 文件的依
赖性,如果找到则再根据那一个规则生成.o 文件。
5、.o文件的依赖是你的 C 文件和 H 文件,于是 make 会编译.c与.h文件生成 .o 文件,然后再用 .o 文件生成 make 的终极任务,也就是执行文件 edit 了。

总结:整个make流程就是一个对比依赖与目标时间,然后寻找依赖生成目标文件的过程,如果在此过程中目标文件的依赖缺失,make便会失败,但如果出现的是命令错误或者是编译失败make并不会终止。make的核心便是一个目标文件寻找依赖的过程,如果一个目标没有依赖那么make就不会去执行,就比如clean,我们必须显示的去调用make clean才可以做到清理文件的功能。于是在我们编程中,如果这个工程已被编译过了,当我们修改了其中一个源文件,比如 file.c,那么根据我们的依赖性,我们的目标 file.o 会被重编译(也就是在这个依性关系 后面所定义的命令),于是 file.o 的文件也是最新的,于是 file.o 的文件修改时间要比edit 要新,所以 edit 也会被重新链接了。如果被更改的是一个头文件,那么包含该头文件的函数都需要重新编译链接。

四、Makefile中使用变量

当我们的工程十分大时,.o文件的数量也随之增大,我们可能需要在多个地方使用.o,比如编译时,链接时,以及clean时,一旦更改一个文件我们需要从三个路径中添加该文件,十分繁琐,因此我们可以使用变量如:objects = main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o ,于是,我们就可以很方便地在我们的 makefile 中以“$(objects)”的方式来使用些中间文件。
改良后的makefile就变成:
objects = main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
edit : $(objects)
cc -o edit $(objects)
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 :
rm edit $(objects)

五、让Makefile自动推导

GNU 的 make 很强大,它可以自动推导文件以及文件依赖关系后面的命令,于是我们就没必
要去在每一个[.o]文件后都写上类似的命令,因为,我们的 make 会自动识别,并自己推导
命令。 只要 make 看到一个[.o]文件,它就会自动的把[.c]文件加在依赖关系中,如果 make
找到一个 whatever.o,那么 whatever.c,就会是 whatever.o 的依赖文件。并且 cc -c
whatever.c 也会被推导出来,于是,我们的 makefile 再也不用写得这么复杂。我们的是新 的 makefile 又出炉了。

objects = main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
edit : $(objects)
cc -o edit $(objects)
main.o : defs.h
kbd.o : defs.h command.h
command.o : defs.h command.h
display.o : defs.h buffer.h
insert.o : defs.h buffer.h
search.o : defs.h buffer.h
files.o : defs.h buffer.h command.h
utils.o : defs.h
.PHONY : clean
clean :
rm edit $(objects)
这种方法,也就是 make 的“隐晦规则”。上面文件内容中,“.PHONY”表示,clean
是个伪目标文件。

六、清空目标文件的规则

每个 Makefile 中都应该写一个清空目标文件(.o 和执行文件)的规则,这不仅便于重
编译,也很利于保持文件的清洁

一般的风格都是:
clean:
rm edit $(objects)
更为稳健的做法是:
.PHONY : clean
clean :
-rm edit $(objects)
前面说过,.PHONY 意思表示 clean 是一个“伪目标”,。而在 rm 命令前面加了一个小
减号的意思就是,也许某些文件出现问题,但不要管,继续做后面的事。当然,clean 的规
则不要放在文件的开头,不然,这就会变成 make 的默认目标,相信谁也不愿意这样。不成
文的规矩是——“clean 从来都是放在文件的最后”。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

举世无双勇

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

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

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

打赏作者

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

抵扣说明:

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

余额充值