Makefile的学习与使用

一、学习makefile之前先要掌握的知识:
1.编译过程
将代码编程程可以执行的程序,需要四个步骤:
预处理->编译->汇编->链接。

每一步的作用:
预处理:将头文件展开,替换代码中的宏定义,条件编译,将代码中的注释删除。
编译:检查代码的语法,变量与函数的声明等,将源文件编程生成汇编文件。
汇编:将汇编文件生成目标文件(cpu可以识别的二进制代码文件)
链接:链接器会在目标文件中寻找函数的实现。
2.gcc的编译过程:

分布编译:

预处理:gcc -E 源文件 -o *.i
编译:gcc -S 源文件 -o *.s
汇编:gcc -c 源文件 -o *.o

选项含义
-E只进行预处理
-S进行与处理和编译
-c进行预处理,编译,汇编
-o file指定生成文件名为file
文件后缀含义
.cc语言文件
.i预处理后的C语言文件
.s编译后的汇编文件
.o目标文件
一步编译:

gcc 源文件 -o 目标文件

总结:源文件通过编译生成 目标文件,在通过链接,将目标文件生成可执行的文件。

二、makefile的介绍:
make的工作过程:
1.make会在当前路径下寻找“makefile”文件。
2.如果找到该文件,会先搜寻文件中的第一个target文件。
3.如果target文件不存在, 或者 target文件所依赖的文件的修改时间比target文件新,则执行command语句。
4、如果target所依赖的文件也不存在的话,那么会寻找以 target所依赖的文件 作为 target的语句, 执行command生成一个依赖文件。

总结:make会一层一层的去找文件的依赖,知道编译出第一个目标文件。在寻找的过程中,如果出现了错误,比如最后的依赖不存在,那么make会直接退出,并报错,但是其他的command 命令错误或者语句错误,make 不会理会,因为,make只关心依赖。

makefile的规则:

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

target表示的是目标,该目标可以是一个.o文件,也可以是一个可执行文件。
prerequisites:表示依赖,就是生成目标所需要的文件。
command:make需要执行的命令
在定义好依赖关系后,后续的那一行定义了如何生成目标文件的操作系统命令,一定要以一个 Tab 键作为开头。

总结:这是一个文件的依赖关系,target中的文件需要依赖prerequisites中的文件,而其生成的规则定义在command中。

makefile示例讲解:
1.该工程中有8个.c文件,和3个.h文件,需要编写一个makefile来告诉make如何编译和链接这些文件:
2.需求:
1.如果这个工程没有被编译过,那么所有的.C文件都要被编译和链接。
2.如果这个工程中的某几个.C文件被修改过,那么我只编译修改过的.C文件,并链接目标程序。
3.如果这个工程中的头文件被修改过了,我们需要编译引用过这些头文件的.C文件,并链接目标程序。

edit: main.o kdb.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 diaplay.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

解析:
\(反斜杠表示换行的意思)
执行make命令就可以生成可执行文件edit.
执行 clean 命令会删除所有的.o文件和edit
但是以上的clean 既没有被其他目标所依赖,又没有依赖,那么command 语句(rm edit $(obj)不会调用),但是我们可以通过显示的“make clean”来调用。

makefile使用变量
如果以上工程需要新添加一个.o文件,那么edit需要重新添加,clean 也需要重新添加,target:.o 也要添加,总共有三个地方需要添加,会显得麻烦,如果工程量很大的话,添加新的目标文件,会更加麻烦,所以为了解决这种问题,可以使用变量,这样易于维护;
声明一个变量叫obj,objects,objs,都可以,用一串字符串表示

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

用“$(obj)”表示使用该变量。
于是,以上可以改良为:

obj = main.o kbd.o command.o display.o \ 
      insert.o search.o files.o utils.o new.o
edit:$(obj)
    cc -o edit  $(obj)
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 diaplay.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
new.o:new.c
    cc -c new.c
clean:
    rm edit $(obj)

如果有新的.o文件加入的话,直接修改obj就可以了。

make的自动推导
GUN下的make很强大,可以自动推导文件和依赖关系以及command,于是我们就没必要在每一个.o文件后面都写上类似的命令,因为make可以自动识别,并推导命令。
只要make 一看到.o文件,就会自动把相对应名字的.c文件加在依赖关系中。如果make找到一个whatever.o ,那么whatever.c就会自动加载到依赖文件中,并且 cc -c whatever.c 也会被推导出来,于是以上又可以改良为:

obj = main.o kbd.o command.o display.o \ 
      insert.o search.o files.o utils.o new.o
edit: $(obj)
    cc -o edit $(obj)
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    
new.o:new.c
.PHONY: clean
clean:
    rm edit $(obj)

这种方法也叫make的“隐晦规则”,上面文件的内容中,“.PHONY”表示,clean是一个伪目标文件。
其实,.h文件也可以进行自动推导。

obj = main.o kbd.o command.o display.o \ 
      insert.o search.o files.o utils.o new.o
edit: $(obj)
    cc -o edit $(obj)
$(obj):defs.h
kbd.o command.o files.o:  defs.h command.h
display.o insert.o search.o files.o: defs.h buffer.h

.PHONY: clean
clean:
    rm edit $(obj)

这种风格的makefile显得简单,但是文件的依赖关系比较复杂。

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

clean:
    rm edit $(obj)

更为稳健的做法是

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

“phony”的意思是假,表示clean是一个伪目标,而在rm命令前面加上一个减号的意思就是,也许某些文件出现了问题,直接跳过,继续做后面的事。。

makefile总结:
1.makefile里面有什么?
主要有五个东西:显示规则,隐晦规则,变量定义,文件指示,注释。
显示规则:包含了 生成的目标的文件,target的依赖文件,生成的命令command
隐晦规则:make的自动推导功能。
变量的定义
文件指示:包含三个部分:a.类似于include 包含另一个makefile;b.类似条件编译,在特定的条件下执行对应的部分;c.定义一个多行的命令。
注释:#,和shell一样。“#”可以进行转义。

tips:makefile中的命令一定要以[Tab]开始,也就是要空一个Tab的距离。

2.makefile的文件名
默认的情况下会在当前目录下查找“Makefile”或“makefile”文件。推荐使用“Makefile”。

当然也可以自定义文件名,可以使用make -f 或 make –file作为参数。如:make -f make.linux make –file make.aix

3.引用其他的makefile

使用include可以包含其他的makefile,被包含的文件会放在当前包含的位置:

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命令开始的时候,会搜寻Inlcude所包含的其他makefile,并把其内容替换到当前位置。如果没有指定路径的话,会现在当前路径查找,如果没有:
1.make 执行的时候有 “-I” 或 “–include -dir”参数,会在指定的参数中查找。
如果make还是无法找到文件,会出现警告信息,但不会报错,继续执行,直到makefile全部读完毕,make会再次尝试读取,如果再无法读取再报错。

可以使用-include < filename >表示忽略错误,继续执行,类似于-rm.

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值