1. makefile 的意义
(1)makefile 用于定义源文件之间的依赖关系 (在阅读开源软件源码时,可通过makefile掌握源码中各个文件之间的关系)
(2)makefile 说明如何编译各个源文件并生成可执行程序。
2. makefile 的规则
(1)makefile 规则的定义
形式1:targets : prerequisites ; command
形式2:targets : prerequisites
' ' command
(2)makefile 规则中各元素的含义
targets 目标
-
-
-
- 通常是需要生成的目标文件名
- make 所需执行的命令名称
-
-
prerequisities 依赖
-
-
-
- 当前目标所依赖的其它目标或文件
-
-
command 命令
-
-
-
- 完成目标所需要执行的命令(系统自带命令 — PATH 环境变量、用户命令 — 自己指定路径)
-
-
(3)规则中的注意事项
targets 可以包含多个目标
-
-
-
- 使用空格对多个目标进行分隔
-
-
prerequisities 可以包含多个依赖
-
-
-
- 使用空格对多个依赖进行分隔
-
-
[Tab] 键: ' '
-
-
-
- 每一个命令行必须以 [Tab] 字符开始
- [Tab] 字符告诉 make 此行是一个命令行
-
-
续行符:
-
-
-
- 可以将内容分开写到下一行,提高程序的可读性
-
-
makefile可以在命令前添加 @ 符号,使该命令静默执行。
(4)一个 makefile 的规则示例
makefile:
all : test @echo "make all" test : @echo "make test"
运行结果:
3. makefile依赖(prerequisites)的规则
(1)当目标对应的文件不存在时,执行对应的命令
(2)当依赖在时间上比项目更新时,执行对应的命令
(3)当依赖关系连续发生时,对比依赖链上的每一个目标
4. makefile编程实验:
第一个make的编译案例:
mian.c源码
//mian.c源码 extern void foo(); int main(void) { foo(); return 0; }
func.c源码
//func.c源码 #include "stdio.h" void foo() { printf("void foo() : hello makefile "); }
makefile源码
//makefile源码 hello.out all : func.o main.o gcc -o hello.out func.o main.o func.o : func.c gcc -o func.o -c func.c main.o : main.c gcc -o main.o -c main.c
运行结果:
结论:
(1)工程开发中可以将 最终可执行文件名和all 同时作为makefile中第一条规则的目标。但最终可执行文件名要放在all之前,make默认使用多个目标中的首个目标。这样做的好处是当默认执行make时,make会自行判断依赖关系有没有发生更新,如果没有就不会重新编译程序。如果这里用all作为目标,由于不存在all这个文件,每次执行make时,第一条规则的命令总会被执行,这与实际不符。如果需要强制编译该程序,执行 make all 即可。
(2)makefile不仅可以用在C/C++中,同样可以用在其它编程语言中,如Java等。makefile只是解决问题的一种方法,但普遍应用于C/C++中。
java源码
//java源码 public class HelloJava { public static void main(String[] args) { System.out.println("Hello Java!"); } }
makefile源码
//makefile源码 HelloJava.class all: HelloJava.java @javac HelloJava.java @java HelloJava
运行结果:
5. 小结
(1)makefile 用于定义源文件之间的依赖关系
(2)makefile 说明如何编译各个源文件并生成可执行程序
(3)makefile 中的目标之间存在连续的依赖关系
(4)依赖存在并且命令执行成功是目标完成的充要条件