make和makefile
概念
make 是一个应用程序
- 解析源程序之间的依赖关系
- 根据依赖关系自动维护编译工作
- 直行宿主操作系统中的各种命令
makefile 是一个描述文件
- 定义一系列的规则来制定源文件编译后的先后顺序
- 拥有特定的语法规则,支持函数定义和函数调用
- 能够直接集成操作系统中的各种命令
make 和makefile之间的关系
-
make 和 makefile 中描述用于指导make 程序如何完成工作
-
make根据makefile中的规则执行命令,最后完成编译输出
makefile入门
2.1.1 简单示例
make的示例
注意:
目标后的命令需要用Tab键(不是四个空格)隔开
hello : echo "hello makefile"
make的使用示例
make -f mf.txt hello
功能说明:
以hello为关键字作为目标查找mf.txt文件并指令hello处的命令
结果:
echo "hello makefile" hello makefile
第一行是make 要直行的命令 第二行是结果。
2.1 helloworld
在linux中直行sudo vim makefile 回车
在文件中输入
hello : echo "hello makefile"
然后打开底行模式,输入wq!退出直行
1 make hello 2 make
第一行的功能说明:
以hello为关键字作为目标查找makefile或makefile文件,并且直行hello处的命令
第一行的功能说明:
查找makefile 或者makefile文件中最顶层目标,并执行最顶层目标的命令
结果:
两种方法此makefile的结果自然是一样的
1 hello : 2 echo "hello makefile" 3 4 test : 5 echo "test" 6 pwd 7 ls
执行
1 make 2 make hello 3 make test
观察结果
2.2 初识makefile的结构
makefile的意义
makefile 用于定义源文件间的依赖关系
makefile 说明如何编译各个源文件并生成可执行文件
依赖的定义
makefile中的元素含义
- targets 通常是需要生成的目标文件名 make 所需执行的命令名称
- prerequisities 当前目标所依赖的其他目标或者文件
- command 完成目标所需要执行的命令
规则中的注意事项
- targets 可以包含多个目标 使用空格对多个目标名进行分隔
- prerequisities 可以包含多个依赖,使用空格对多个依赖进行分隔
- [tab]键 :‘\t’ 每个命令行必须以[tab]字符开始,[tab]字符告诉make此行是一个命令行
- 续行符:\ 可以姜内容分开写到下一行,提高可读性
示例1
1 hello :test 2 echo "hello" 3 test : 4 echo "test"
结果实现打印 test hello的依赖是test,所以先执行test,test 没有依赖 所以执行对应的命令
依赖规则:
- 当目标对应的文件不存在,执行对应命令
- 当依赖在时间上比目标新,执行对应命令
- 当依赖关系发生时,对比依赖上的每一个目标
技巧:makefile中可以在命令前加上@符号,作用位命令无回显
示例2
1 //func.c 2 3 #include<stdio.h> 4 5 void func() 6 { 7 printf("func \n"); 8 return ; 9 } 10 11 //main.c 12 13 #include<stdio.h> 14 15 int main() 16 { 17 func(); 18 printf("main\n"); 19 return 0; 20 }
如上,我们目前有了两个.c文件
1 hello.out : main.o func.o 2 gcc -o hello.out main.o func.o 3 main.o : main.c 4 gcc -o main.o main.c 5 func.o : func.c 6 gcc -o func.o func.c
执行make ,func.c main.c的打印都打出来了
当依赖在时间上比目标新,执行对应命令,反之,得不执行命令;在次执行make我们可以根据命令的回显,func.o main.o 两条命令没有执行。
因为我们没有修改这个.c文件,func.o main.o的时间比对应的.c文件新,所以没有必要执行命令,这个也比较好理解。但是我们再次执行make
hello.out 对应的指令又执行了。
技巧:工程中开发可以将最终可执行文件名和all同时作为makefile的第一条规则的目标
1 hello.out all : main.o func.o 2 gcc - o hello.out main.o func.o
如果代码没有修改,多次make,也不会执行命令了。
3.1伪目标
默认情况下
make认为目标对应这一个文件
make比较目标文件和依赖关系的新旧关系,决定是否执行命令
make以文件处理作为第一优先级
1 clean : 2 rm *.o hello.out 3 4 #执行make 5 make clean 6
此目录中如果有一个clean文件,如果执行make clean 则会一直提示clean 是最新的没有更新,如果没有clean文件,此目录
下面的*.o将会被删除。
伪目标
通过.PHONY 关键字生命一个伪目标
伪目标不对应任何实际的文件
不管伪目标的依赖是否更新,命令总是执行
伪目标的的语法 先声明,后使用
本质:
伪目标是make中特殊目标.PHONY的依赖
1 .PHONY : clean 2 clean : 3 sudo rm *.o hello.out
执行make clean的时候 会把.o hello.out删掉,ls ll 下确实没有.o .out 文件
伪目标的妙用:规则调用(函数调用)
1 .PHONY : clean rebuild all 2 rebulid : clean all
执行make rebuild的时候会先执行clean 然后执行all 对应的命令
原理:当一个目标的依赖包含伪目标时,伪目标所定义的命令总会被执行
技巧:绕开.PHONY关键字作为伪目标
clean : FORCE sudo rm *.o hello.out FORCE :
原理:
如果一个规则没有命令或者依赖,并且他的目标不是一个存在的文件名;在执行此规则时,目标总会被认为是最新的。
4 变量与赋值方式
4.1makefile变量
- makefile中支持程序设计语言的变量的概念
- makefile中的变量只代表文本数据(字符串)
- makefile中变量名规则
- 变量名可以包含字符,数字,下划线
- 不能包含 “:” ,“#” ,“=” 或 “ ”
- 变量名大小写敏感
变量的定义和使用
代码示例
1 CC := gcc 2 TARGET := hello-world.out 3 4 $(TARGET) : func.o main.o 5 $(CC) -o $(TARGET) func.o main.o 6 7 func.o : func.c 8 $(CC) -o func.o -c func.c 9 10 main.o : main.c 11 $(CC) -o main.o -c main.c 12 13 .PHONY : rebuild clean all 14 15 rebuild : clean all 16 17 18 all : $(TARGET) 19 20 clean : 21 rm *.o $(TARGET) 22 23
CC 此处是gcc 我们可以修改成g++ 或交叉编译(arm-linux-gccXXXX)这样就很方便了,不用挨着修改
目标名也是,如果想换一个目标名,那我们可以修改变量的值就行了。
4.2makefile中变量的赋值方式
- 简单赋值(:=) (可以理解为c语言中=)
- 递归赋值(=) (可以理解为c语言指针赋值)
- 条件赋值 (?=) (可以理解为C++的引用赋值)
- 追加赋值 (+=) (可以理解为c语言+=)