makefile与c语言的学习(一)

makefile 定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为makefile 就像一个 Shell 脚本一样,其中也可以执行操作系统的命令。
自动化编译
make 是一个解释makefile中指令的命令工具。一般大多数IDE都有这个命令,比如linux 下GNU的make
makefile里面包含了5个东西:
(1)显示规则
要生成的文件,文件的依赖文件,生成的命令。
(2)隐性规则
make就有自动推导功能
(3)变量的定义
与shell脚本中的变量定义和引用相同
(4)文件指示
1、在一个makefile中引用另一个makefile,类似于c中的include
2、根据某些情况指定执行makefile中的有效部分,类似于c中的预编译#if
3、定义一个多行的命令
(5)注释
与shell脚本相同,其注释是用"#"符号,如果要在Makefile 中使用“#”字符,可以用反斜框进行转义,如:“#”

target ... : prerequisites ...
command
...
...

target 也就是目标文件,(可以是Object File,也可以是执行文件,还可以是一个标签)
prerequisites生成目标文件所需要的文件或目标
command 是make执行的命令(任意的shell命令)

一、一个makefile示例
一个工程有 3 个头文件,和 8 个 C 文件

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

反斜杠( \ ) 换行符,使得makefile易读。将此内容保存为makefile 文件,然后直接输入命令make就可以生成执行文件edit。如果要删除执行文件和所有中间目标文件,只需执行make clean即可。
(1)在makefile中的依赖关系中,说明了1、由头文件和C文件生成.O文件->编译,汇编 2、最后由.O文件生成执行文件edit->链接。
(2)后续定义了如何生成目标文件的操作系统命令,但是注意需要用tab键作为开头,make只执行所定义的命令,而且make 会比较 targets 文件和 prerequisites 文件的修改日期,如果 prerequisites 文件的日期要比 targets 文件的日期要新,或者 target 不存在的话,那么,make 就会执行后续定义的命令。

clean不是一个文件,而是一个动作名字,其冒号后什么也没有,make就不会自动去寻找文件的依赖性,也就不会自动执行其后所定义的命令。要执行其后的命令,就要在make 命令后明显得指出这个lable的名字。(这样就可以在makefile 中定义不用编译或者与编译无关的命令)

二、make如何工作
在默认情况下,只需输入make命令
1、make 会在当前目录下找名字叫“Makefile”或“makefile”的文件。
2、如果找到,首先会寻找目标文件target ,并把这个文件作为最终的目标文件;如果目标文件不存在,或者依赖文件修改的时间比执行文件新,就会执行后面所定义的命令来生成可执行文件。

make会一层层找文件的依赖关系,直到最终生成目标文件。如果在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,make就会直接退出,并报错,make只注重于文件的依赖性。
(于是如果这个工程已经编译过了,当修改其中一个源文件,比如file.c,根据依赖性,file.o文件也会被重编译,而同样edit可执行文件也会重新链接。如果改变的是command.c,那么,kdb.o、command.o 和 files.o 都会被重编译,
并且edit 会被重链接)

三、makefile 中使用变量
[.o]文件的字符串在makefile中被重复引用了3次,所以我们可以使用一个变量来代替减小make的复杂度。
变量引用与shell脚本中相同:

objects = main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o

所以之后的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)

而且如果由新的.o文件加入,只需修改objects变量即可

四、make的自动推导
make 可以自动推导文件以及文件依赖关系后面的命令,于是没必要在每一个[.o]文件后都写上类似的命令,因为make 会自动识别,并自己推导命令。
只要make 看到一个[.o]文件,它就会自动的把[.c]文件加在依赖关系中,如果 make找到一个 whatever.o,那么 whatever.c,就会是 whatever.o 的依赖文件。并且 cc -c whatever.c 也会被推导出来,于是,我们的 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)

以上内容中,“.PHONY”表示,clean是个伪目标文件。

五、清空目标文件

clean:
	rm edit $(objects)

或者

.PHONY : clean
clean :
	-rm edit $(objects)

在 rm 命令前面加了一个小减号的意思就是,也许某些文件出现问题,但不要管,继续做后面的事。注意clean 从来都是放在文件最后的。

六、makefile文件
(1)makefile文件名:默认的情况下,make 命令会在当前目录下按顺序找寻文件名为 “GNUmakefile”、“makefile”、“Makefile”的文件。但是最好不要使用 “GNUmakefile” ,这个文件是 GNU 的 make 识别的。
也可以使用别的文件名来书写makefile,当指定使用makefile时,使用make的 -f 或者 --file 命令,如:make -f Make.Linux 或 make --file Make.AIX。

(2)引用其他的makefile:使用include关键字可以把其他的makefile包含进来,include的语法是:include < filename >
filename 可以是当前操作系统 Shell 的文件模式(可以保含路径和通配符) 在 include前面可以有一些空字符,但是绝不能是[Tab]键开始。include 和< filename >可以用一个或多个空格隔开。
例如:有这样几个 Makefile:a.mk、b.mk、c.mk,还有一个文件叫foo.make,以及一个变量$(bar),其包含了 e.mk 和 f.mk

include foo.make *.mk $(bar)

等价于:

include foo.make a.mk b.mk c.mk e.mk f.mk

如果文件都没有指定绝对路径或是相对路径的话,make 会在当前目录下首先寻找,如果当前目录下没有找到,那么,make 还会在下面的几个目录下找:
1、如果 make 执行时,有“-I”或“–include-dir”参数,那么 make 就会在这个参数所指定的目录下去寻找。
2、如果目录< prefix >/include(一般是:/usr/local/bin 或/usr/include)存在的话,make 也会去找。

如果想让 make不管那些无法读取的文件,而继续执行,你可以在 include 前加一个减号“-”,无论include发生什么错误,都不会报错继续执行。即:
-include < filename >

所以GNU make的工作步骤:
1、读入所有的 Makefile。
2、读入被 include 的其它 Makefile。
3、初始化文件中的变量。
4、推导隐晦规则,并分析所有规则。
5、为所有的目标文件创建依赖关系链。

6、根据依赖关系,决定哪些目标要重新生成。
7、执行生成命令。

发布了54 篇原创文章 · 获赞 4 · 访问量 1050

猜你喜欢

转载自blog.csdn.net/buzhiquxiang/article/details/103387494