一、什么是Makefile?
用于工程项目管理的一个文本文件,文件名为Makefile的文本文件
Makefile文件首字母可以大写,也可以小写,一般使用大写的Makefile .
如果Makefile和makefile文件都存在,执行make命令时,默认执行小写的makefile文件.
二、什么是make?
make是一个执行Makefile的工具,是一个解释器,当执行make命令时,
会解析Makefile文件中的依赖关系,通过依赖关系最终执行编译相关的命令,
完成对整个项目代码的编译。
make可执行程序在/usr/bin目录下(默认ubuntu系统都自带make命令)
sudo apt-get install make
三、Makefile的用途?
描述了整个工程了的编译、链接规则
软件项目自动化编译
四、理论基础
软件构造过程、程序的编译和链接
面向依赖的思维(思想)
编译代码的4个阶段:预处理 ---> 编译 ---> 汇编 ---> 链接
1.预处理:头文件的展开、注释的删除、宏定义的替换
gcc -E xxx.c -o xxx.i
2.编译:词法分析、语法分析 --查错的
如果无误,会生成汇编文件
gcc -S xxx.i -o xxx.s
3.汇编:将汇编文件生成二进制文件
gcc -c xxx.s -o xxx.o
4.链接:链接需要用到的库文件,最终生成可执行文件
链接库需要加编译选项 -l
gcc xxx.o -o a.out
面向依赖的思想:
得到.elf可执行文件-依赖-> ***.o -依赖-> ***.s -依赖-> ***.i -依赖-> ***.c
五、Makefile的工作过程?
源文件 --> 编译 --> 目标文件 --> 链接 --> 可执行文件
hello.c -----> hello.o -----> hello
Makefile编译源文件分成两步?
1》本质上可以通过一步直接生成可执行文件。
通过一步编译完成,最终生成可执行文件:
gcc score.c main.c -o stu_manage
缺点:只要修改一个.c文件,,其他的.c文件都会被重新编译,浪费时间。
2》分成两部目的是。
对于大型工程文件,源文件很多,如果修改某个
源文件,当你再次执行make的时候,如果源文件
没有修改,make是不会重新生成目标文件,
只有修改过的源文件才会重新生成目标文件,
最后进行链接即可,这样可以有效的节约代码的编译时间。
通过两步编译完成,最终生成可执行文件:
第一步:(-c:只编译不链接,将.c文件编译生成.o文件)
gcc -c score.c -o score.o
gcc -c main.c -o main.o
第二步:(链接:将所有的.o文件链接生成可执行文件)
gcc score.o main.o -o stu_manage
优点:如果修改了一个.c文件只需要重新编译修改过的.c文件将其生成.o文件,
最后将所有的.o文件重新链接生成可执行文件即可。
Makefile文件如何知道源文件是否修改呢?根据文件的时间戳
六、规则的构成
-
规则基本构成(由三部分组成)
目标
目标依赖
命令 -
语法格式
目标:目标依赖
命令注意事项:
命令必须使用tab键开头、一般是shell命令
一个规则中可以无目标依赖,仅仅实现某种操作
一个规则中可以没有命令,仅仅描述依赖关系
一个规则中必须有一个目标
#案例:
# 规则:只有目标和目标只来,用来描述依赖的关系
all:hello
# 规则:有目标,有目标依赖,有命令,即描述了依赖关系,又完成某种操作。
hello:hello.o
gcc hello.o -o hello
hello.o:hello.c
gcc -c hello.c -o hello.o
# 规则:有目标,没有依赖,有命令,为了完成某种操作
clean:
rm hello.o hello
七、Makefile实例
1.我们现在有两个文件,score.c和main.c,需要将两个.c文件编译生成一个可执行文件stuManager。
对于我们常规的做法,就是:gcc score.c main.c -o stuManager就可以了。那么怎么用Makefile来实现呢?
#写法1
stuManager:main.o score.o
gcc main.o score.o -o stuManager
main.o:main.c
gcc -c main.c -o main.o
score.o:score.c
gcc -c score.c -o score.o
clean:
rm *.*[^ch] stuManager
2.第一种写法,感觉也不是很方便,有没有更方便一点的写法呢?
当然是有的,不过在这里要先说一下:$@代表目标,$^代表所有依赖,那么第一种方法就可以简化为如下形式。
#写法2
stuManager:main.o score.o
gcc $^ -o $@
main.o:main.c
gcc -c $^ -o $@
score.o:score.c
gcc -c $^ -o $@
clean:
rm *.*[^ch] stuManager
3.我们会发现第2种写法中,执行的命令都一样,那么还有没有办法进行进一步的合并呢?也是有的。其中,% 代表模式匹配。
#写法3
stuManager:main.o score.o
gcc $^ -o $@
# % :模式匹配,后边一个%号对应的字符串和前边的%代表的是同一个字符串
%.o:%.c
gcc -c $^ -o $@
clean:
rm *.*[^ch] stuManager
4.上面的写法已经很简单了,但是这时候我们又会发现一个问题:现在目标stuManager的依赖只有main.o score.o两个文件,那么如果此时需要的依赖文件又多了一个呢?这个时候,就要再手动添加一个新的依赖文件,那如果多的是5个,10个呢?每次都手动添加,也显得很麻烦。
那么这个时候,我们就要用到两个函数了wildcard和patsubst。
用法示例:
$(wildcard *.c)
返回值为当前目录下所有.c 源文件列表。
$(patsubst %.c, %.o, a.c b.c)
把字串“a.c b.c”中以.c 结尾的单词替换成以.o 结尾的字符。
函数的返回结果是“a.o b.o”
#写法4
#返回值为当前目录下所有.c 源文件列表。
var := $(wildcard *.c)
#将字符串$(var)中以.c 结尾的文件名替换成以.o 结尾的文件名。
obj := $(patsubst %.c, %.o, $(var))
stuManager:$(obj)
gcc $^ -o $@
# % :模式匹配,后边一个%号对应的字符串和前边的%代表的是同一个字符串
%.o:%.c
gcc -c $^ -o $@
clean:
rm *.*[^ch] stuManager
总结
以上就是对Linux下Makefile实现的简单讲解与实现,不足之处还望大家指出,谢谢大家。