- 代码变成可执行文件,叫做编译(compile);先编译这个,还是先编译那个(即编译的安排),叫做构建(build)。
- Make命令依赖Makefile文件里的命令进行构建,也可以自定义构建文件,如:指定make命令依据rules.txt文件中的规则,进行构建。
$ make -f rules.txt # 或者 $ make --file=rules.txt
- 要考虑的问题:要构建哪个文件?它依赖哪些源文件?当那些文件有变动时,如何重新构建它?
- 穿插gcc相关指令
-g 可执行程序包含调试信息
-o 指定输出文件名
-c 只编译不链接,产生.o文件,就是obj文件,不产生执行文件
-pipe 使用管道代替编译中临时文件
-S 对源代码进行预处理、编译,不执行汇编、链接工作,有时我们想查看源代码的汇编代码,可以通过-S 选项实现
-E 仅对源代码进行预处理(比如替换宏),这个选项不会像之前一样产生一个文件,而是直接将结果输出到屏幕
-D 定义宏,与源代码中#define指令定义的宏效果一样。
-v 将编译过程中运行细节显示在屏幕上(错误输出stderr),可以将编译器的每步工作细节都展现出来
-Wall 使GCC产生尽可能多的警告信息
警告信息虽然不能算作错误,但却很可能成为错误的来源。一个好的程序员应该尽量避免产生警告信息,使自己的代码始终保持标准、健壮。所以应将警告信息当成编码错误来对待
如果在编译程序时带上-Werror选项,那么GCC会在产生警告时停止编译
-I 指定头文件包含目录
-L 指定库文件目录,假定在/home/jie/lib目录下动态库文件libadd.so和静态库文件libadd.a
-std= 指定语言标准
GCC提供不同等级的代码优化功能。开关选项是:-On,n取值为0到3。默认为1。-O0表示没有优化,而-O3是最高优化。优化级别越高代码运行越快,但并不是所有代码都能够加载最高优化,而应该视具体情况而定。但一般都使用-O2选项,因为它在优化长度、编译时间和代码大小之间,取得了一个比较好的平衡点。
详细指令
举例:
max_num.exe: max_num.o max.o gcc -o max_num.exe max_num.o max.o max_num.o: max_num.c max.h gcc -c max_num.c max.o: max.c max.h gcc -c max.c
- 每行命令之前必须有一个tab键。如果想用其他键,可以用内置变量.RECIPEPREFIX声明。
-
模式匹配
%.o: %.c
支持三个通配符:*, ?, [...]
。可以用在规则中,也可以用在变量中
-
变量和赋值符
VARIABLE = value
# 在执行时扩展,允许递归扩展。
VARIABLE := value
# 在定义时扩展。
VARIABLE ?= value
# 只有在该变量为空时才设置值。
VARIABLE += value
# 将值追加到变量的尾端。
$@指代当前目标
$< 指代第一个前置条件
$? 指代比目标更新的所有前置条件,之间以空格分隔
$^ 指代所有前置条件,之间以空格分隔
$* 指代匹配符 % 匹配的部分
$(@D) 和 $(@F) 分别指向 $@ 的目录名和文件名
$(<D) 和 $(<F) 分别指向 $< 的目录名和文件名
-
判断和循环
Makefile使用 Bash 语法,完成判断和循环
语法
<条件语句>
<true 执行语句>
else
<false 执行语句>
endif
其中条件语句有四种情形:
1、表示是否相等
ifeq (<arg1>, <arg2>) # 推荐
ifeq '<arg1>' '<arg2>'
ifeq "<arg1>" "<arg2>"
2、表示是否不等,上面的 ifeq 换成 ifneq
3、ifdef
4、ifndef
-
常用函数
字符串替换
$(subst <from>, <to>, <text>)
模式字符串替换
$(patsubst <pattern>, <replacement>, <text>)
去开头和结尾的空格
$(strip <string>)
查找字符串
$(findstring <find>, <in>)
反过滤
$(filter-out <pattern_or_string>, <text>)
排序(单词升序)
$(sort <list>)
取单词
$(word <n>, <text>)
取单词串
$(wordlist <n_start>, <n_end>, <text>)
单词个数统计
$(words <text>)
去掉每个单词的最后文件名部分,只剩下目录部分
$(dir <names ...>)
去掉每个单词的目录部分,只剩下文件名部分
$(notdir <names ...>)
读取各文件名的后缀
$(suffix <names ...>)
加后缀
$(addsuffix <suffix>, <names ...>)
加前缀
加前后缀在动态创建局部变量很有用$(addprefix <prefix>, <names ...>)
连接字符串
$(join <list1>, <list2>)
for 循环
$(foreach <var>, <list>, <text>)
这其实是一个函数,作用是:将 list
的单词逐一取出,放到 var
指定的变量中,然后执行 text
的表达式。返回值则是 text
的最终执行值。
shell 函数
执行 shell 命令,并且将 stdout 作为返回值返回,如:contents := $(shell ls -la)
控制 make 输出
$(error <text ...>)
$(warning <text ...>)
这也同时是调试和定位 make 的好方法。
判断文件是否存在
ifeq ($(FILE), $(wildcard $(FILE)))
...
endif
参考链接:
https://www.ruanyifeng.com/blog/2015/02/make.html
https://segmentfault.com/a/1190000012091117