在平时瞎搞中,经常会遇到GNU工具的一些知识,毕竟GNU和Linux关系紧密。这些工具和知识点对于开发Linux是必不可少的基础,每次忘记了都要谷歌一把,不如记在自己的空间里,方便检索。
Makefile
先来看Makefile。
Makefile基本形式
1 | target: dependencies |
Makefile隐式规则
GNU Makefile包含一些默认的规则,通常被称作隐式规则(implicit rules)。
一些常见的隐式规则如下:
.o
files can be obtained from.c
files by compilation. 也就是说可以不用显式的为生成 “XX.o” 文件编写规则,make 会自动的从对应的 “XX.c” 文件编译得到 “.o” 文件- an executable can be made by linking together
.o
files clean
has no dependencyclean
andall
are special targets- when call
make
with no arguments, the first target in the makefile is built - CC === C compiler
- CXX === C++ compiler
- CFLAGS === the compilation options for C programs
- CXXFLAGS === the compilation options for C++ programs
- CPPFLAGS === the C PreProcesser options
下面是一个最简单的Makefile示例:
1 | CC=gcc |
变量赋值
Makefile中提供了多种变量赋值方式,来看下常用的几种以及它们的区别。
语法 | 含义 | 说明 |
---|---|---|
:= | Simple assignment | 赋值一次,到处使用;首次遇到变量的时候进行初始化,初始化后变量值保持不变 |
= | Recursive assignment | 次次使用,次次更新;每次遇到变量,都重新对变量的值进行评估(赋值中使用了其他变量),变量的值会发生变化 |
?= | Conditional assignment | 只有当变量没有值的时候,才会将给定的值赋给变量 |
+= | Appending | 追加文本到已有的变量 |
Makefile通配符和特殊变量
为了使Makefile更通用,在实际编写中会大量使用通配符和特殊变量,来替代Makefile中与某个特定项目相关的文件名、目标名等。这样,Makefile就不受源代码文件的增减、重命名等的影响了,这就是通配符的神奇作用了。
通配符
通配符
%
用于文件名模式匹配,提供通用的targets1
2
3
4
5
6%.o: %.c
actions
# When % appears in the dependency list,
# it is replaced with the same string that was used to
# perform substitution in the target.出现在依赖列表中的 % 会被替换为目标中 % 对应的字符串 (单看.o和.c的话,根据前面的隐式规则,是不是就需要写了?)
特殊变量
在 actions/commands 中,通常使用特殊变量
来匹配文件名。常用的特殊变量如下:
Special variables | Meaning |
---|---|
$@ |
full target name of the current target |
$? |
returns the dependencies that are newer than the current target |
$* |
returns the text that corresponds to % int the target |
$< |
name of the first dependency |
$^ |
name of all the dependencies with space as the delimiter |
PHONY用法
前面提到 all
和 clean
是Makefile中的特殊目标,但是如果当前项目目录中恰好有文件的名字是 all 和 clean呢?
这个时候就需要使用 .PHONY
指令来指定哪些目标不能做被当作文件:
1 | .PHONY all clean |
模拟执行
有时候需要调试Makefile,但仅仅想跟踪make的执行来查看log,并不想真正运行相关的动作,毕竟编译还是很耗时的。
通过简单的执行 make -n
来做一次“dry run”就可以了。
在变量中使用shell命令
有时我们需要使用shell命令的输出结果,形式如下:
1 | LS_OUT = $(shell ls) |
未完待续…