Makefile:
跟我一起写Makefile:
https://seisman.github.io/how-to-write-makefile/overview.html
Makefile中的include命令详解
https://www.cnblogs.com/cuckoos/articles/5049984.html
一 什么是makefile
一个工程中的源文件不计其数,并且按类型、功能、模块分别放在若干个目录中,手动编译的话伤神又费力,还非常容易出错。
所以makefile定义了一系列的规则,来控制通过怎么样的编译方法去生成指定的文件从而解决庞大工程的编译问题。
同时,Makefile中支持绝大部分shell命令,可以在一定程度上免去附加shell脚本的麻烦
二 makefile的执行与规则
1. 当执行make时的操作步骤
(1) make -> 匹配文件 -> 按照文件内的规则执行
(2) make -> 匹配文件中的目标参数 -> 按照文件内的规则执行
2. make执行中匹配文件的规则
a. 默认的情况下,make命令会在当前目录下按顺序找寻文件名为“GNUmakefile”、“makefile”、“Makefile”的文件。最好使用“Makefile”这个文件名 。
b. 当然,可以使用别的文件名来书写Makefile,比如:“Make.Linux”“Make.Solaris”,“Make.AIX”等,如果要指定特定的Makefile,你可以使用make的 -f 或 --file 参数,如: make -f Make.Linux 或 make --file Make.AIX 。
3.Makefile的书写规则
Target : prerequisites ……
command
...
......
Target (目标):可以是一个object file(目标文件),还可以是一个标签。
Prerequisites (依赖/前提)生成该target所依赖的文件和/或target
Command (命令)该target要执行的命令(任意的shell命令)
规则的本质 – Makefile的核心内容: prerequisites中如果有一个以上的文件比target文件要新的话,prerequisites 及 command所定义的命令就会被执行。
4. 简单示例
target : main.o display.o search.o
gcc main.o display.o search.o -o target
main.o : main.c
gcc -c main.c
display.o : display.c defs.h
gcc -c display.c
search.o : search.c buffer.h
gcc -c search.c
clean :
rm target main.o display.o search.o
5. 执行过程
不同于C语言的顺序执行过程
通读makefile,建立依赖链表
运行高优先级操作
确定目标(第一个),递进执行
6. 伪目标
在Makefile中,存在于目标的位置,但是并不是真正存在的文件,就称之为伪目标
伪目标存在的意义:
make 指定参数完成我们指定的功能。
意外情况:
clean是我们的伪目标,但是当前目录下不巧正好存在名字是clean的文件,此时,clean动作将不会执行(clean后没有依赖,无法比较新旧)
解决->关键词 .PHONY:
.PHONY : clean
clean:
rm target main.o display.o search.o
7. 打印信息:
Command内
命令本身会显示
<TAB>echo “XXXX”
全局
$(warning xxxxx)
一般用于告警信息输出,带行号
$(error xxxxx)
错误输出,带行号,终止运行
8. 屏蔽信息:
屏蔽Makefile中的命令显示
使用“@”符号
make 参数 -s 或 --silent 或 –quiet 全面禁止命令的显示
9. 异常出错处理
Make在执行时,遇到错误默认是要终止的
当前规则下的一个命令出错的话,整个Makefile都会因此而停止。
a. 忽略执行结果,始终认为是成功的。
在命令前加符号“-”
Make使用参数-i 或 --ignore-errors
规则以.IGNORE 作为目标,命令不停
b. 出错时停止当前规则,继续执行下一条规则
make使用参数-k 或是 --keep-going时,本规则停止但不退出Makefile
10. 变量的简单使用
可以发现,规则中存在大量的重复字符串,如果我们更改或者再加入一个文件,那就要在最少三个地方(还有clean中)进行改动。随着工程的变大,修改和维护越来越复杂。
使用变量可以解决此种问题
Makefile中的变量具有多种定义方法:
= 全文最后赋值生效
:= 调用前的赋值生效
?= 之前未定义时则赋值
+= 在之前的定义之上追加,不同于C语言的+=
Makefile中的变量和shell中的变量有异曲同工之处。
变量的定义无需提前声明类型,直接赋值即可。 object = xxxxxx
使用时需要使用$,最好加括号
11. Makefile简化-自动推导
它可以自动推导文件以及文件依赖关系后面的命令。make看到目标为.o 文件时,它的产生方式cc -c 会被推导出来。
12. Makefile简化-隐含规则
在make中约定好的,不需要在Makefile中写出来的规则。
13. Makefile简化-隐含规则&模式规则
类似于一般的规则,但是在规则的目标定义需要有“%”字符。“%”字符代表的意思是一个或多个任意字符。
14. 特殊的自动化变量
$@ : 目标文件集。
$< : 依赖文件集
如果是以模式(即 % )定义的,那么 将是符合模式的一系列的文件集。并且是一个一个取出来的。
%.o : %.c
cc –c $< -o $@
$% : 仅当目标是函数库文件中,表示规则中的目标成员名。例如,如果一个目标是 foo.a(bar.o) ,那么, $% 就是 bar.o , $@ 就是 foo.a 。如果目标不是函数库文件(Unix下是 .a ,Windows下是 .lib ),那么,其值为空。
$^ : 所有的依赖目标的集合。以空格分隔。如果在依赖目标中有多个重复的,那么这个变量会去除重复的依赖目标,只保留一份。
$+ : 这个变量很像 $^ ,也是所有依赖目标的集合。只是它不去除重复的依赖目标。
$* : 这个变量
15. 条件判断
语法:
<conditional-directive>
<true>
else
<false>
endif
<conditional-directive> 表示条件关键字
一共有4个:
ifeq
ifneq
ifdef
ifndef
16. 函数
函数调用语法:
$(<function> <arguments>)
或是:
${<function> <arguments>}
来源:
自定函数
define 函数名(XXX)
函数体
endef
内建函数:
字符串处理函数
文件名操作函数
Foreach函数(循环用)
If函数
Call函数(创建新参数化函数)
Origin函数(获取变量来源)
Shell函数(执行shell命令,将结果返回)
17. 高级操作
规则高级操作:
文件搜寻特殊变量VPATH
多目标
静态模式
自动生成依赖性
命令高级操作:
嵌套执行make
引用其他makefile
变量高级操作:
多层变量
变量值替换
追加变量值 += 和 :=
override 指示符
多行变量
环境变量
目标变量
模式变量
Make的参数:
-b,-m
-B,--always-make
-c
--debug,-d
-e
-f
-h
-I
-I
-j
…..
18. install 命令:
install命令和cp命令类似,都可以将文件/目录拷贝到指定的地点。但是,install允许你控制目标文件的属性